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.Domain.Configurations;
    using Shared.EntityModels;
    using Shared.UserModels.WebNotification;

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

        /// <summary>
        /// The running environment
        /// </summary>
        private readonly IRunningEnvironment runningEnvironment;

        /// <inheritdoc cref="IWebNotificationService" />
        public WebNotificationServices(IUnitOfWork unitOfWork, IRunningEnvironment runningEnvironment)
        {
            this.unitOfWork = unitOfWork;
            this.runningEnvironment = runningEnvironment;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<RoleModel>> GetAllRoles()
        {
            var query = $@"Select * from ""Role"" where ""Active"" is true";
            return await this.unitOfWork.Current.QueryAsync<RoleModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<AccountModel>> FetchAccountBasedonName(string fullName)
        {
            var query = $@"Select * from ""Account"" where ""FullName"" ilike '%{fullName}%' and ""Active"" is true";
            return await this.unitOfWork.Current.QueryAsync<AccountModel>(query);
        }


        /// <inheritdoc/>
        public async Task<int> InsertAsync(WebNotificationModel model)
        {
            var where = $@"where 1=1 and ""ModulesMasterId"" = {model.ModulesMasterId}";
            if (model.ReferenceId != null)
            {
                where += $@" and ""ReferenceId"" = {model.ReferenceId}";
            }
            if (model.PatientId != null)
            {
                where += $@" and ""PatientId"" = {model.PatientId}";
            }
            var checkIfQuery = $@"select count(*) from ""WebNotification"" {where} ";
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return 0;
            }

            var notification = new WebNotification
            {
                // Should save with comma  seperated.
                AllowedAccounts = model.AllowedAccounts,
                AllowedRoles = model.AllowedRoles, // Should save with comma seperated
                CreatedDate = model.CreatedDate != null ? model.CreatedDate : DateTime.Now,
                IsRead = false,
                Message = model.Message,
                RedirectionLink = model.RedirectionLink,
                WebNotificationLogTypeId = model.WebNotificationLogTypeId,
                WebNotificationPriorityId = model.WebNotificationPriorityId,
                PatientId = model.PatientId, // If Notification is patient related 
                ReferenceId = model.ReferenceId, // in case redirection needed
                ModulesMasterId = model.ModulesMasterId
            };
            try
            {
                var response = await this.unitOfWork.WebNotifications.InsertAsync(notification);
                return response;
            }
            catch (Exception e)
            {
                e.Message.ToString();
            }

            return 1;
        }

        /// <inheritdoc/>
        public async Task<int> UpdateAsync(WebNotificationModel model, int BookScanAppointmentId)
        {
            var updateResponse = -1;
            var notification = await this.unitOfWork.WebNotifications.FindAsync(m => m.ReferenceId == BookScanAppointmentId && m.ModulesMasterId == model.ModulesMasterId);
            if (notification != null)
            {
                var updateModel = await this.unitOfWork.WebNotifications.FindAsync(x => x.WebNotificationId == notification.WebNotificationId);
                updateModel.CreatedDate = model.CreatedDate;
                updateModel.Message = model.Message;
                updateResponse = await this.unitOfWork.WebNotifications.UpdateAsync(updateModel);
            }
            return updateResponse;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<WebNotificationDisplayModel>> FetchNotificatons(WebNotificationFilterModel model)
        {
            var where = $@"Where 1=1 and WB.""IsRead"" is false";
            var extraCondition = string.Empty;
            var extraConditionScan = string.Empty;
            var extraColumn = string.Empty;
            var filterPatient = string.Empty;

            if (model.ShowRead)
            {
                where = $@" Where 1=1 ";
            }

            if (model.RoleId > 0)
            {
                where += $@" and R.""RoleId"" = {model.RoleId} ";
            }

            if (model.PatientId != null)
            {
                where += $@" and WB.""PatientId"" = {model.PatientId} ";
            }

            if (!string.IsNullOrEmpty(model.FilterPatient))
            {
                filterPatient += $@" Where (TRIM(UPPER(m.""PatientName"")) ILIKE '%{model.FilterPatient.Trim().ToUpper()}%' OR m.""PatientMobile"" ILIKE '%{model.FilterPatient.Trim().ToUpper()}%' OR m.""UMRNo"" ILIKE '%{model.FilterPatient.Trim().ToUpper()}%')";
            }

            if (model.FromDate != null)
            {
                where += $@" and WB.""CreatedDate""::date >= '{model.FromDate?.ToString("yyyy-MM-dd")}'::date ";
            }

            if (model.ToDate != null)
            {
                where += $@" and WB.""CreatedDate""::date <= '{model.ToDate?.ToString("yyyy-MM-dd")}'::date ";
            }

            if (model.ProviderId != null)
            {
                where += $@" and APT.""ProviderId"" = {model.ProviderId} ";
            }

            if (model.ModuleType != null)
            {
                where += $@" and MM.""ModuleName"" ilike '{model.ModuleType}%'";
            }
            if (model.LocationId != null) // Only applicable if this is for appointment/Scans
            {
                where += $@" and (APT.""LocationId"" = {model.LocationId} or BSA.""LocationId"" = {model.LocationId})";
            }

            if (model.ProviderId != null || model.LocationId != null)
            {
                extraColumn += $@" , APT.""PaymentStatus"", APT.""Active""";
                extraCondition += $@" left join ""Appointment"" APT on APT.""AppointmentId"" =  WB.""ReferenceId"" "; // and APT.""PaymentStatus"" is false
            }

            if (model.ScanMachineMasterId != null || model.LocationId != null)
            {
                extraColumn += $@" , BSA.""PaymentStatus"" AS ""ScanPaymentStatus""";
                extraConditionScan += $@" left join ""BookScanAppointment"" BSA on BSA.""BookScanAppointmentId"" =  WB.""ReferenceId"" AND BSA.""PaymentStatus"" IS FALSE AND BSA.""Active"" IS TRUE AND BSA.""Status"" != 'C'";
            }

            if (model.ModuleIdNotToDisplay != null)
            {
                where += $@" and MM.""ModulesMasterId"" != {model.ModuleIdNotToDisplay}";
            }

            var query = $@"with mainData as(SELECT distinct WB.""WebNotificationId"",WB.""Message"", WB.""WebNotificationPriorityId"", WB.""WebNotificationLogTypeId"", WB.""CreatedDate"",
		                        WB.""RedirectionLink"", WB.""AllowedRoles"", WB.""AllowedAccounts"", WB.""IsRead"", WB.""PatientId"",WB.""ReferenceId"",
		                        WNP.""Priority"",WNL.""LogType"",P.""FullName"" as ""PatientName"", P.""Age"" as ""PatientAge"",P.""Gender"" as ""PatientGender"",P.""Mobile"" as ""PatientMobile"",
		                        P.""UMRNo"",WB.""ModulesMasterId"" as ""WebNotificationTypeId"",MM.""ModuleName"" as ""ModuleType"",
		                        (CASE WHEN P.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE '' END) AS ""PatientThumbnailUrl""
                                {extraColumn}
	                        FROM ""WebNotification"" WB
	                        join ""WebNotificationPriority"" WNP on WNP.""WebNotificationPriorityId"" = WB.""WebNotificationPriorityId""
	                        join ""WebNotificationLogType"" WNL on WNL.""WebNotificationLogTypeId"" = WB.""WebNotificationLogTypeId""
                            join ""ModulesMaster"" MM on MM.""ModulesMasterId"" = WB.""ModulesMasterId""	                        
                            join ""Role"" R on R.""RoleId"" = any(string_to_array(WB.""AllowedRoles"",',')::int[])
	                        left join ""Patient"" P on P.""PatientId"" = WB.""PatientId""
                            {extraCondition}
                            {extraConditionScan}
	                        {where}  
	                        order by WB.""CreatedDate"" desc)
                            Select count(m.*) over() as ""TotalItems"",m.* from mainData m
                            {filterPatient}";

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

        /// <inheritdoc/>
        public async Task<int> UpdateReadStatus(int referenceId, int modulesMasterId)
        {
            var query = $@"update ""WebNotification"" set ""IsRead"" = true where ""ReferenceId"" = {referenceId} and ""ModulesMasterId"" ={modulesMasterId} ";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }
    }
}