namespace Hims.Infrastructure.Services
{
    using System;
    using System.Linq;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Domain.Entities.ProviderMedication;
    using Shared.UserModels.ProviderMedication;

    /// <inheritdoc />
    public class ProviderMedicationServices : IProviderMedicationService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="IProviderMedicationService" />
        public ProviderMedicationServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        ///<inheritdoc/> 
        public async Task<int> AddProviderMedicationInBulk(ProviderMedicationGroupModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();

            var groupModel = new ProviderMedicationGroup
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                SpecializationId = model.SpecializationId,
                TagName = model.TagName
            };

            var checkIf = string.Empty;

            if (!string.IsNullOrEmpty(model.TagName))
            {
                checkIf = $@"Select * from ""ProviderMedicationGroup"" where lower(""TagName"") = '{model.TagName.ToLower()}'";
            }
            else
            {
                checkIf = $@"Select * from ""ProviderMedicationGroup"" where ""SpecializationId"" = {model.SpecializationId}";
            }

            var group = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderMedicationGroup>(checkIf);
            if (group != null)
            {
                groupModel.ProviderMedicationGroupId = group.ProviderMedicationGroupId;
            }
            else
            {
                groupModel.ProviderMedicationGroupId = await this.unitOfWork.ProviderMedicationGroups.InsertAsync(groupModel, transaction);
                if (groupModel.ProviderMedicationGroupId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            var medicationMasters = new List<ProviderMedicationMaster>();

            foreach (var m in model.Medicines)
            {
                var master = new ProviderMedicationMaster
                {
                    AfternoonDosage = m.AfternoonDosage,
                    Dosage = m.Dosage,
                    Duration = m.Duration,
                    DurationType = m.DurationType,
                    Instruction = m.Instruction,
                    IsAfternoon = m.IsAfternoon,
                    IsMorning = m.IsMorning,
                    IsNight = m.IsNight,
                    MorningDosage = m.MorningDosage,
                    NightDosage = m.NightDosage,
                    PharmacyProductId = m.PharmacyProductId,
                    ProviderMedicationGroupId = groupModel.ProviderMedicationGroupId
                };

                var checkIfProductExistsQuery = $@"select * from ""ProviderMedicationMaster"" where ""PharmacyProductId"" = {master.PharmacyProductId} and ""ProviderMedicationGroupId"" = {master.ProviderMedicationGroupId} ";
                var checkIfProductExists = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderMedicationMaster>(checkIfProductExistsQuery);
                if (checkIfProductExists != null)
                {
                    master.ProviderMedicationMasterId = checkIfProductExists.ProviderMedicationMasterId;
                }
                else
                {
                    master.ProviderMedicationMasterId = await this.unitOfWork.ProviderMedicationMasters.InsertAsync(master, transaction);
                    if (master.ProviderMedicationMasterId == 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }

                medicationMasters.Add(master);
            }

            if (!string.IsNullOrEmpty(model.ProviderIds))
            {
                var doctors = model.ProviderIds.Split(",");
                foreach (var medication in medicationMasters)
                {
                    var mapModel = doctors.Select(x => new ProviderMedicationMap
                    {
                        Active = true,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        ProviderId = Convert.ToInt32(x),
                        ProviderMedicationMasterId = medication.ProviderMedicationMasterId
                    });
                    var mapResponse = await this.unitOfWork.ProviderMedicationMaps.BulkInsertAsync(mapModel, transaction);
                    if (mapResponse == 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            transaction.Commit();
            return groupModel.ProviderMedicationGroupId;
        }

        ///<inheritdoc/> 
        public async Task<IEnumerable<ProviderMedicationMasterModel>> FetchAddedMedicationAsync(ProviderMedicationMasterModel model)
        {
            var where = "where 1=1";
            if(model.AppointmentId != null)
            {
                where += $@" and (pmm.""ProviderMedicationMasterId"" in (select ""ProviderMedicationMasterId"" from ""ProviderMedicationMap"" where ""ProviderId"" in (
                                                select ""ProviderId"" from ""Appointment"" where ""AppointmentId"" = {model.AppointmentId}))
                                        or pmm.""ProviderMedicationMasterId"" not in (select ""ProviderMedicationMasterId"" from ""ProviderMedicationMap""))";
            }

            var query = $@"SELECT count(pmm.""ProviderMedicationMasterId"") over() as ""TotalItems"",pmm.""ProviderMedicationMasterId"", pmm.""ProviderMedicationGroupId"", pmm.""PharmacyProductId"", pmm.""Duration"", pmm.""DurationType"", pmm.""IsMorning"", pmm.""IsAfternoon"",
                                   pmm.""IsNight"", pmm.""MorningDosage"", pmm.""AfternoonDosage"", pmm.""NightDosage"", pmm.""Dosage"", pmm.""Instruction"",
                                   pp.""ProductName"" ,pp.""GenericName"", C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"", pmg.""TagName"",s.""SpecializationName"",pmg.""SpecializationId"" 
                                   FROM ""ProviderMedicationMaster"" pmm
	                            join ""PharmacyProduct"" pp on pp.""PharmacyProductId"" = pmm.""PharmacyProductId"" 
	                            join ""Company"" C on C.""CompanyId"" = pp.""CompanyId""
	                            join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                            join ""ProviderMedicationGroup"" pmg ON pmg.""ProviderMedicationGroupId"" = pmm.""ProviderMedicationGroupId"" 
	                            left join ""Specialization"" s on s.""SpecializationId"" = pmg.""SpecializationId""
                                {where}
	                            order by pmm.""ProviderMedicationMasterId"" desc";
            if(model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0? model.PageIndex - 1: model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

            var response = await this.unitOfWork.Current.QueryAsync<ProviderMedicationMasterModel>(query);

            foreach(var item in response)
            {
                item.Providers = new List<ProviderList>();
                var queryProvider = $@"SELECT p.""FullName"" ,p.""ProviderId"" 
                                                FROM ""ProviderMedicationMap"" pmm
                                                join ""Provider"" p on p.""ProviderId"" = pmm.""ProviderId"" 
                                                where pmm.""ProviderMedicationMasterId"" = {item.ProviderMedicationMasterId}";
                var providers = await this.unitOfWork.Current.QueryAsync<ProviderList>(queryProvider);
                item.Providers = providers.ToList();
            }

            return response;
        }

        ///<inheritdoc/> 
        public async Task<IEnumerable<string>> GetAllTagsAsync()
        {
            var query = $@"select ""TagName"" from ""ProviderMedicationGroup"" where ""TagName"" is not null";
            return await this.unitOfWork.Current.QueryAsync<string>(query);
        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int? providerMedicationMasterId)
        {
            var query = $@"DELETE FROM ""ProviderMedicationMaster"" WHERE ""ProviderMedicationMasterId""= {providerMedicationMasterId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }
        
        /// <inheritdoc />
        //public async Task<int> UpdateAsync(ProviderMedicationMasterModel model)
        //{
            //var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""VisitTypeId"") FROM ""VisitType"" WHERE TRIM(UPPER(""VisitorName"")) = '{model.ProviderMedicationMasterId.ToUpper().Trim()}' AND ""VisitTypeId"" <> {model.ProviderMedicationMasterId}");
            //if (checkIf > 0)
            //{
            //    return -1;
            //}

            //var visitType = await this.unitOfWork.Visitors.FindAsync(m => m.VisitTypeId == model.ProviderMedicationMasterId);
            //visitType.VisitorName = model.VisitorName;
           // visitType.VisitTypeFor = model.VisitTypeFor;
            //visitType.Active = true;
            //visitType.ModifiedBy = model.ModifiedBy;
            //visitType.ModifiedDate = DateTime.Now;
           // return await this.unitOfWork.Visitors.UpdateAsync(visitType);
       //}
    }
}
