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;
    using Shared.EntityModels;
    using Shared.UserModels.Filters;

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

        /// <inheritdoc cref="IInsuranceTemplateService" />
        public InsuranceTemplateService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<InsuranceTemplateModel>> FetchAsync(InsuranceTemplateFilterModel model)
        {
            var where = " WHERE 1 = 1 ";

            if (model.InsuranceCompanyId > 0)
            {
                where += $@" AND IT.""InsuranceCompanyId"" = {model.InsuranceCompanyId}";
            }
            if (model.ChargeModuleTemplateId > 0)
            {
                where += $@" AND IT.""ChargeModuleTemplateId"" = {model.ChargeModuleTemplateId}";
            }
            if (model.InsuranceTemplateId > 0)
            {
                where += $@" AND IT.""InsuranceTemplateId"" = {model.InsuranceTemplateId}";
            }
            if (model.TpaId > 0)
            {
                where += $@" AND IT.""TpaId"" = {model.TpaId}";
            }


            if (!string.IsNullOrEmpty(model.TemplateName))
            {
                where += $@" and CT.""TemplateName"" ilike '%{model.TemplateName}%' ";
            }
            if (model.LocationId > 0)
            {
                where += $@" AND CT.""LocationId""  = {model.LocationId}";
            }

            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"", IT.""InsuranceTemplateId"", IT.""ChargeModuleTemplateId"", IT.""InsuranceCompanyId"", IT.""TpaId"", IT.""Active"",IT.""CreatedBy"", IT.""CreatedDate"", IT.""ModifiedBy""
                                ,IT.""ModifiedDate"",CA.""FullName"" AS ""CreatedByName"" , MA.""FullName"" AS ""ModifiedByName"" , CT.""TemplateName"", TP.""Name"" as ""TpaName"", IC.""FullName"" as ""InsuranceCompanyName"", IT.""AdmissionPayTypeId"", PT.""AdmissionPayTypeName"" 
                                From ""InsuranceTemplate"" IT
                                Join ""ChargeModuleTemplate"" CT on CT.""ChargeModuleTemplateId"" = IT.""ChargeModuleTemplateId""
                                Join ""InsuranceCompany"" IC on IC.""InsuranceCompanyId"" = IT.""InsuranceCompanyId""
                                Join ""Tpa"" TP on TP.""TpaId"" = IT.""TpaId""
                                Left Join ""Account"" CA ON CA.""AccountId"" = IT.""CreatedBy""         
                                Left Join ""Account"" MA ON MA.""AccountId"" = IT.""ModifiedBy""
                                Left Join ""AdmissionPayType"" PT ON PT.""AdmissionPayTypeId"" = IT.""AdmissionPayTypeId""
                                {where} Order by IT.""InsuranceTemplateId"" DESC";
            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<InsuranceTemplateModel>(query);
            }

            model.PageIndex -= 1;
            query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            return this.unitOfWork.Current.QueryAsync<InsuranceTemplateModel>(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<Resource>> FetchInsuranceTemplateAsync(InsuranceTemplateFilterModel model)
        {
            var where = " WHERE 1 = 1 ";
            if (model.InsuranceCompanyId > 0)
            {
                where += $@" AND F.""FloorId"" = {model.InsuranceCompanyId}";
            }
            if (model.LocationId > 0)
            {
                where += $@" and F.""LocationId"" = {model.LocationId}";
            }
            var query = $@"SELECT COUNT(*) OVER () AS ""TotalItems"",W.""Active"",
                        W.""InsuranceTemplateId"" AS ""Id"",W.""WardName"" AS ""Value"" ,F.""FloorName"" AS ""OptionalText1"", L.""Name"" AS ""OptionalText""
                                FROM ""Ward"" W
                                JOIN ""Floor"" F on F.""FloorId""=W.""FloorId""
                                 Join ""Location"" L on F.""LocationId"" = L.""LocationId""
                                {where} and  W.""Active"" = true Order by ""InsuranceTemplateId"" DESC";
            return this.unitOfWork.Current.QueryAsync<Resource>(query);
        }


        /// <inheritdoc />
        public async Task<int> AddAsync(InsuranceTemplateModel model)
        {

            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""InsuranceTemplateId"")  FROM ""InsuranceTemplate"" WHERE ""InsuranceCompanyId"" = '{model.InsuranceCompanyId}' and ""ChargeModuleTemplateId"" ={model.ChargeModuleTemplateId} and ""TpaId"" = {model.TpaId} and ""Active"" is true ");
            if (checkIf > 0)
            {
                return -1;
            }
            var insuranceTemplate = new InsuranceTemplate
            {
                Active = true,
                InsuranceCompanyId = model.InsuranceCompanyId,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                ChargeModuleTemplateId = model.ChargeModuleTemplateId,
                TpaId = model.TpaId,
                AdmissionPayTypeId = model.AdmissionPayTypeId
            };

            var insuranceTemplateId = await this.unitOfWork.InsuranceTemplates.InsertAsync(insuranceTemplate);
            return insuranceTemplateId;
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(InsuranceTemplateModel model)
        {

            var insuranceTemplate = await this.unitOfWork.InsuranceTemplates.FindAsync(m => m.InsuranceTemplateId == model.InsuranceTemplateId);
            insuranceTemplate.ChargeModuleTemplateId = model.ChargeModuleTemplateId;
            insuranceTemplate.Active = model.Active;
            insuranceTemplate.ModifiedBy = model.ModifiedBy;
            insuranceTemplate.ModifiedDate = DateTime.Now;
            insuranceTemplate.InsuranceCompanyId = model.InsuranceCompanyId;
            insuranceTemplate.TpaId = model.TpaId;
            insuranceTemplate.AdmissionPayTypeId = model.AdmissionPayTypeId;

            return await this.unitOfWork.InsuranceTemplates.UpdateAsync(insuranceTemplate);
        }

        /// <inheritdoc />
        public async Task<int> DeleteAsync(int insuranceTemplateId)
        {

            var query = $@"DELETE FROM ""InsuranceTemplate"" WHERE ""InsuranceTemplateId""= {insuranceTemplateId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<string> FindNameByInsuranceTemplateId(int insuranceTemplateId)
        {
            var query = $@"SELECT ""InsuranceTemplateId"" FROM ""InsuranceTemplate"" WHERE ""InsuranceTemplateId"" = {insuranceTemplateId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        /// <summary>
        /// Changes the status asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        public async Task<int> ChangeStatusAsync(InsuranceTemplateModel model)
        {

            var insuranceTemplate = await this.unitOfWork.InsuranceTemplates.FindAsync(m => m.InsuranceTemplateId == model.InsuranceTemplateId);
            if (insuranceTemplate == null)
            {
                return -1;
            }
            insuranceTemplate.Active = model.Active;
            insuranceTemplate.ModifiedBy = model.ModifiedBy;
            insuranceTemplate.ModifiedDate = DateTime.Now;
            return await this.unitOfWork.InsuranceTemplates.UpdateAsync(insuranceTemplate);
        }

    }
}