namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels;
    using Hims.Shared.UserModels.OrderPrescription;
    using Shared.EntityModels;
    using Shared.UserModels.Filters;

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

        /// <inheritdoc cref="IWardService" />
        public OrderPrescriptionService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        public async Task<int> AddAsync(ViewModel model)
        {
            try
            {
                var order = new OrderPrescriptionValue
                {
                    Active = true,
                    ValueName = model.ValueName,
                    Comments = model.Comments,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    OrderPrescriptionMasterId = model.OrderPrescriptionMasterId
                };

                return await this.unitOfWork.OrderPrescriptionValues.InsertAsync(order);
            }catch (Exception ex)
            {
                throw;
            }
        }

        public async Task<int> UpdateAsync(ViewModel model)
        {
            var record = await this.unitOfWork.OrderPrescriptionValues.FindAsync(m => m.ValueId == model.ValueId);
            record.ValueName = model.ValueName;
            record.Comments = model.Comments;
            record.Active = true;
            record.ModifiedBy = model.ModifiedBy;
            record.ModifiedDate = DateTime.Now;
            record.OrderPrescriptionMasterId = model.OrderPrescriptionMasterId;
            return await this.unitOfWork.OrderPrescriptionValues.UpdateAsync(record);
        }

        public async Task<IEnumerable<ViewModel>> FetchOrderAsync(ViewModel model)
        {
            var where = $@" where  1=1";
            if (model.EncounterTypeId != 0)
            {
                where += $@" and op.""EncounterTypeId"" ={model.EncounterTypeId}";
            }
            if (model.ProviderId != 0)
            {
                where += $@" and  ( op.""ProviderId"" in ( {model.ProviderId}) or  op.""ProviderId"" is  null)";
            }
            var query = $@"select op.""OrderPrescriptionMasterId"",op.""Name"" as ""OrderName"",op.""Name"",op.""Active"",op.""CreatedBy"",op.""CreatedDate"",op.""ModifiedBy"",op.""ModifiedDate"",
                    a.""FullName"" as ""CreatedByName"",c.""FullName"" as ""ModifiedByName"", op.""EncounterTypeId"", op.""ProviderId"", et.""EncounterName""
                    from ""OrderPrescriptionMaster"" op
                    left Join ""Account"" a on a.""AccountId"" = op.""CreatedBy""
                    left join ""Account"" c on c.""AccountId"" = op.""ModifiedBy"" 
                    left join ""EncounterType"" et on et.""EncounterTypeId""=op.""EncounterTypeId""
					{where}";

            return await this.unitOfWork.Current.QueryAsync<ViewModel>(query);
        }

        public Task<int> DeleteAsync(int valueId)
        {
            var query = $@"DELETE FROM ""OrderPrescriptionValue"" WHERE ""ValueId""= {valueId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<string> FindNameByValueId(int valueId)
        {
            var query = $@"SELECT ""ValueId"" FROM ""OrderPrescriptionValue"" WHERE ""ValueId"" = {valueId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        public async Task<IEnumerable<ViewModel>> FetchAsync(ViewModel model)
        {
            var where = $@" where  1=1";
            if (model.EncounterTypeId != null)
            {
                where += $@" and et.""EncounterTypeId"" ={model.EncounterTypeId}";
            }
            if (model.OrderPrescriptionMasterId != 0)
            {
                where += $@" and  p.""OrderPrescriptionMasterId"" = {model.OrderPrescriptionMasterId}";
            }
            var query = $@"select Count(*) OVER() AS ""TotalItems"",   p.""ValueName"",p.""ValueId"",m.""Name"" as ""OrderName"",p.""OrderPrescriptionMasterId"",p.""Comments"",p.""CreatedBy"",p.""CreatedDate"",p.""ModifiedDate"",p.""ModifiedBy"",a.""FullName"" as ""CreatedByName"",c.""FullName"" as ""ModifiedByName"", et,""EncounterName""
                        from ""OrderPrescriptionValue"" p
                        left join ""OrderPrescriptionMaster"" m on m.""OrderPrescriptionMasterId"" = p.""OrderPrescriptionMasterId""
                        join ""Account"" a on a.""AccountId"" = p.""CreatedBy""
                        left join ""Account"" c on c.""AccountId"" = p.""ModifiedBy""
                        left join ""EncounterType"" et on et.""EncounterTypeId""=m.""EncounterTypeId"" 
                        {where}";
            if (model.PageIndex <= 0)
            {
                return await this.unitOfWork.Current.QueryAsync<ViewModel>(query);
            }
            model.PageIndex -= 1;
            //query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";

            return await this.unitOfWork.Current.QueryAsync<ViewModel>(query);
          
        }

        public async Task<IEnumerable<ViewModel>> FetchTypesAsync(ViewModel model)
        {
            var where = $@" where 1=1";
            if (model.Type != null)
            {
                where += $@" and m.""Name"" ilike '%{model.Type}%'";
            }
            if(model.SearchParam != null)
            {
                where += $@" and p.""ValueName"" ilike '%{model.SearchParam}%'";
            }
            if(model.EncounterTypeId != null && model.EncounterTypeId>0)
            {
                where += $@" and m.""EncounterTypeId"" ={model.EncounterTypeId}";
            }
            var query = $@"select p.""ValueName"",p.""ValueId"",m.""Name"" as ""OrderName"",p.""OrderPrescriptionMasterId"",p.""Comments"",p.""CreatedBy"",p.""CreatedDate"",p.""ModifiedDate"",p.""ModifiedBy"",a.""FullName"" as ""CreatedByName"",c.""FullName"" as ""ModifiedByName"" 
 from ""OrderPrescriptionValue"" p
 left join ""OrderPrescriptionMaster"" m on m.""OrderPrescriptionMasterId"" = p.""OrderPrescriptionMasterId""

 join ""Account"" a on a.""AccountId"" = p.""CreatedBy""
left join ""Account"" c on c.""AccountId"" = p.""ModifiedBy"" {where}";
            return await this.unitOfWork.Current.QueryAsync<ViewModel>(query);
        }

        public async Task<int> AddOrderMaster(OrderPrescriptionMasterModel model)
        {
            var query = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int> ($@"select count(*) from ""OrderPrescriptionMaster"" where ""EncounterTypeId""={model.EncounterTypeId} and ""Name""='{model.Name}' ");
            if(query >0)
            {
                return -1;
            }
            try
            {
                var order = new OrderPrescriptionMaster
                {
                    Active = true,
                    Name=model.Name,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    EncounterTypeId= (int)model.EncounterTypeId,
                    ProviderId=model.ProviderId,
                };

                return await this.unitOfWork.OrderPrescriptionMasters.InsertAsync(order);
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        public async Task<int> UpdateOrderMaster(OrderPrescriptionMasterModel model)
        {
            var query = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"select count(*) from ""OrderPrescriptionMaster"" where ""EncounterTypeId""={model.EncounterTypeId} and ""Name""='{model.Name}'and ""OrderPrescriptionMasterId"" <>{model.OrderPrescriptionMasterId}");
            if (query > 0)
            {
                return -1;
            }
            var record = await this.unitOfWork.OrderPrescriptionMasters.FindAsync(m => m.OrderPrescriptionMasterId == model.OrderPrescriptionMasterId);
            record.Name = model.Name;
            record.Active = true;
            record.ModifiedBy = model.ModifiedBy;
            record.ModifiedDate = DateTime.Now;
            record.ProviderId = model.ProviderId;
            record.EncounterTypeId = (int)model.EncounterTypeId;
            return await this.unitOfWork.OrderPrescriptionMasters.UpdateAsync(record);
        }


        public async Task<IEnumerable<OrderPrescriptionMasterModel>> FetchOrderMaster(OrderPrescriptionMasterModel model)
        {
            var query = "";
            var where = " WHERE 1 = 1 ";
            if (model.EncounterTypeId != null)
            {
                where += $@" AND opm.""EncounterTypeId"" = {model.EncounterTypeId}";
            }
            if (model.ProviderId != null)
            {
                where += $@" AND pr.""ProviderId"" = {model.ProviderId}";

            }
            if (model.Name != null)
            {
                where += $@" AND opm.""Name""='{model.Name}'";
            }
            query = $@"select COUNT(*) OVER () AS ""TotalItems"",  opm.""OrderPrescriptionMasterId"" ,opm.""Name"",opm.""Active"",opm.""CreatedBy"",opm.""CreatedDate"",opm.""ModifiedBy"",opm.""ModifiedDate"",a.""FullName"" as ""CreatedByName"",c.""FullName"" as ""ModifiedByName"" ,opm.""EncounterTypeId"",
                pr.""FullName"" as ""ProviderName"", e.""EncounterName"",pr.""ProviderId""
                from ""OrderPrescriptionMaster"" opm
                left join ""Provider"" pr on pr.""ProviderId""=opm.""ProviderId""
                left join ""EncounterType"" e on e.""EncounterTypeId""=opm.""EncounterTypeId""
                join ""Account"" a on a.""AccountId"" =opm.""CreatedBy""
                left join ""Account"" c on c.""AccountId"" = opm.""ModifiedBy"" {where} ";

            if (model.PageIndex <= 0)
            {
                return await this.unitOfWork.Current.QueryAsync<OrderPrescriptionMasterModel>(query);
            }
            model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
            query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            return await this.unitOfWork.Current.QueryAsync<OrderPrescriptionMasterModel>(query);
        }

        public Task<int> DeleteOrderMaster(int valueId)
        {
            var query = $@"DELETE FROM ""OrderPrescriptionMaster"" WHERE ""OrderPrescriptionMasterId""= {valueId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

       public async Task<int> AddEncounterOrderTemplates(EncounterOrderTemplatesModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterTemplateId"") FROM ""EncounterOrderTemplates"" WHERE  Lower(""TemplateName"") = '{model.TemplateName.ToLower()}' and ""EncounterTypeId"" = {model.EncounterTypeId} ");
            if (checkIf > 0)
            {
                return -2;
            }
            var EncounterOrderTemplates = new EncounterOrderTemplates()
            {
                EncounterTypeId = (int)model.EncounterTypeId,
                TemplateName = model.TemplateName,
                Description = model.Description,
                CreatedBy =(int) model.CreatedBy,
                CreatedDate = DateTime.Now,
                Active = true
            };
            
            var result = await this.unitOfWork.EncounterOrderTemplates.InsertAsync(EncounterOrderTemplates);

                return result;

        }

       public async Task<int> UpdateEncounterOrderTemplates(EncounterOrderTemplatesModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterTemplateId"") FROM ""EncounterOrderTemplates"" WHERE  Lower(""TemplateName"") = '{model.TemplateName.ToLower()}' and ""EncounterTypeId"" = {model.EncounterTypeId} ");
            if (checkIf > 0)
            {
                return -2;
            }
            var EncounterOrderTemplates = this.unitOfWork.EncounterOrderTemplates.Find(s => s.EncounterTemplateId == model.EncounterTemplateId);
            if (EncounterOrderTemplates == null)
            {
                return -2;
            }
            EncounterOrderTemplates.EncounterTemplateId = (int)model.EncounterTemplateId;
            EncounterOrderTemplates.EncounterTypeId =(int) model.EncounterTypeId;
            EncounterOrderTemplates.TemplateName = model.TemplateName;
            EncounterOrderTemplates.Description = model.Description;
            EncounterOrderTemplates.ModifiedBy = model.ModifiedBy;
            EncounterOrderTemplates.ModifiedDate = DateTime.Now;

            var result = await this.unitOfWork.EncounterOrderTemplates.UpdateAsync(EncounterOrderTemplates);
            return result;

        }

        public  Task<IEnumerable<EncounterOrderTemplatesModel>> GetEncounterOrderTemplates(EncounterOrderTemplatesModel model)
        {

            string where = "where 1=1 ";

            var Query = $@"	 select count(*) over () as ""TotalItems"", EOT.""EncounterTemplateId"", EOT.""EncounterTypeId"", EOT.""Description"",EOT.""TemplateName"",EOT.""Active"",A.""FullName"" as ""CreatedByName"",
			   EOT.""CreatedDate"", B.""FullName"" as ""ModifiedByName"",EOT.""CreatedBy"",EOT.""ModifiedBy"" , EOT.""ModifiedDate"" ,ET.""EncounterName"" as ""EncounterTypeName""
			   from  ""EncounterOrderTemplates"" EOT
			   join ""Account"" A  on A.""AccountId"" = EOT.""CreatedBy""
			   left join ""Account"" B on B.""AccountId"" = EOT.""ModifiedBy""
               left join ""EncounterType"" ET on ET.""EncounterTypeId"" = EOT.""EncounterTypeId"" {where} order by EOT.""EncounterTemplateId"" desc " ;

            if (model.PageSize != null && model.PageIndex != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                Query += $@" limit {model.PageSize} offset {model.PageIndex * model.PageSize}";
            }
            return  this.unitOfWork.Current.QueryAsync<EncounterOrderTemplatesModel>(Query);
        }
       public async Task<int> ChangeEncounterOrderTemplateStatus(EncounterOrderTemplatesModel model)
        {
            var OldEncounterOrderTemplate = await this.unitOfWork.EncounterOrderTemplates.FindAsync(l => l.EncounterTemplateId == model.EncounterTemplateId);
            OldEncounterOrderTemplate.Active = (bool)!model.Active;
            OldEncounterOrderTemplate.ModifiedBy = model.ModifiedBy;
            OldEncounterOrderTemplate.ModifiedDate = DateTime.Now;

            var result = await this.unitOfWork.EncounterOrderTemplates.UpdateAsync(OldEncounterOrderTemplate);
            return result;
        }
    }
}