namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    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 Newtonsoft.Json;
    using Hims.Shared.UserModels.Scan.ScanAppointment;
    using Hims.Shared.UserModels.OperationTheater;

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

        /// <inheritdoc cref="IProviderLocationService" />
        public OTRegisterService(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        public Task<int> ActivateOrDeactivateTest(OTRegisterInsertModel model)
        {
            throw new NotImplementedException();
        }

        public Task<IEnumerable<OTRegisterFilterModel>> FetchAllAsync(OTRegisterFilterModel model)
        {           
                var where = $@"where 1=1";
            if (!string.IsNullOrEmpty(model.OTRoomId))
            {
                where += $@"  and  otr.""OTRoomId"" in ({model.OTRoomId})";
            }
            if (model.AppointmentStatus == false)
            {
                where += $@" and otr.""Status"" not in ('C')";
            }
            if ((model.SurgeryId!=0) && (model.SurgeryId!=null))
            {
                where += $@"  and  otr.""SurgeryId"" in ({model.SurgeryId})";
            }
            if ((model.LocationId != 0) && (model.LocationId != null))
            {
                where += $@"  and  otr.""LocationId"" in ({model.LocationId})";
            }
            if (!string.IsNullOrEmpty(model.FromDate) && string.IsNullOrEmpty(model.FromDate))
            {
                where += $@" and otr.""CreatedDate"" = '{model.FromDate}'";
            }

            if (!string.IsNullOrEmpty(model.FromDate) && !string.IsNullOrEmpty(model.ToDate))
            {
                where += $@" AND otr.""SignInDate""::DATE >= '{model.FromDate}'::DATE";
                where += $@" AND otr.""SignOutDate""::DATE <= '{model.ToDate}'::DATE"; 
            }
            var query = $@"	select otr.""OTRegisterId"" ,otr.""PatientId"" ,otr.""SurgeryId"" , otr.""ProviderId"" ,otr.""SurgeryTypeId"" ,    otr.""Remarks""   ,  otr.""OREntryDate"",  
TO_CHAR(otr.""SignInDate"",'yyyy-dd-MM FMHH12:MI am') as ""StartTime""  ,otr.""SignInDate"",otr.""SignOutDate"",  TO_CHAR(otr.""SignOutDate"",'FMHH12:MI am') as ""EndTime"",  otr.""ShiftWardToDate"",  
otr.""Address"" ,otr.""CreatedBy"" ,TO_CHAR(otr.""CreatedDate"",'yyyy-dd-MM FMHH12:MI am') as ""CreatedDate"" ,otr.""ModifiedBy"" , otr.""ModifiedDate"" ,
otr.""OTRoomId"",     otr.""Status"" ,    otr.""Reason"" ,    otr.""LocationId""  ,otr.""OldAppointmentDate"" ,
s.""Name"" as OperationName,st.""SurgeryName"" as OperationType,p.""FullName"" as Patient,pr.""FullName"" as Surgeon,CA.""FullName"" AS ""CreatedByName"",
--anType.""Name"" as AnaesthesiaType,
	--a.""FullName""  as Assistant,an.""FullName""	as Anaesthetist,n.""FullName""  as Nurse,CA.""FullName"" AS ""CreatedByName"" ,
--MA.""FullName"" AS ""ModifiedByName"" ,
ot.""RoomName""
	from ""OTRegister"" otr
left join ""OTRoom"" ot on ot.""OTRoomId""=otr.""OTRoomId""
	left join ""Surgery"" s on s.""SurgeryId""=otr.""SurgeryId""
	left join ""SurgeryType"" st on st.""SurgeryTypeId""=otr.""SurgeryTypeId""
	left join ""Patient""  p on	p.""PatientId""=otr.""PatientId""
	left join ""Provider"" pr on pr.""ProviderId""=	otr.""ProviderId""
--left join ""AnaesthesiaType"" anType on anType.""AnaesthesiaTypeId""=	otr.""AnaesthesiaTypeId""
	Left Join ""Account"" CA ON CA.""AccountId"" = otr.""CreatedBy""         
    -- Left Join ""Account"" MA ON MA.""AccountId"" = otr.""ModifiedBy""
	--left join ""Account"" a 	on a.""AccountId""=otr.""AssitantId"" and a.""RoleId""={model.AssistantRoleId }::int
	--left join ""Account"" an on  an.""AccountId""=otr.""AnaesthetistId"" and an.""RoleId""={model.AnaesthistRoleId }::int
	--left join ""Account"" 	n on n.""AccountId""=otr.""NurseId"" and n.""RoleId""={model.NurseRoleId }::int 
{where}";            
            return this.unitOfWork.Current.QueryAsync<OTRegisterFilterModel>(query);
            

            }
       
        public async Task<int> InsertAsync(OTRegisterInsertModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            try

            {
                var OtRegister = new OTRegister
                {
                    OTRegisterId = model.OTRegisterId,
                    PatientId = model.PatientId,
                    ProviderId = model.ProviderId,
                    // AssitantId = model.AssitantId,
                    //AnaesthetistId = model.AnaesthetistId,
                    //AnaesthesiaTypeId = model.AnaesthesiaTypeId,
                    //NurseId = model.NurseId,
                    SurgeryId = model.SurgeryId,
                    //SurgeryTypeId = model.SurgeryTypeId,
                    //Diagnosis = model.Diagnosis,
                    Remarks = model.Remarks,
                    OREntryDate = model.OREntryDate,
                    SignInDate = model.SignInDate,
                    SignOutDate = model.SignOutDate,
                    ShiftWardToDate = model.ShiftWardToDate,
                    //CaseTypeId = model.CaseTypeId,
                    Active = true,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    OTRoomId = model.OTRoomId,
                    Status = "B",
                    LocationId = model.LocationId

                };
                OtRegister.OTRegisterId = await this.unitOfWork.OTRegisters.InsertAsync(OtRegister);
                if (OtRegister.OTRegisterId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                //if (OtRegister.OTRegisterId > 0)
                //{
                //    //transaction for the Scan Appointment
                //    var commonTransaction = new AppointmentTransaction
                //    {
                //        AppointmentId = OtRegister.OTRegisterId,
                //        Transaction =  "",
                //        TransactionDate = DateTime.Now,
                //        //TransactionId = model.TransactionId ?? await appointmentTransactionsServices.GetATransactionId(),
                //        // VoucherNumber = model.SalucroStatusCode == 1201 ? null : await appointmentTransactionsServices.GetVoucherNumber(),
                //        BankReference = "",
                //        BankCode = "",
                //        Active = true,
                //        PaymentId = 0,
                //        PaymentModeId = 1,
                //        // SettledAmount = Convert.ToDecimal(model.Amount),
                //        CreatedBy = model.CreatedBy,
                //        CreatedDate = DateTime.Now,
                //        LocationId = model.LocationId,
                 //           PatientId

                //    };
                //    commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                //    if (commonTransaction.AppointmentTransactionId == 0)
                //    {
                //        transaction.Rollback();
                //        return 0;
                //    }                   
                //}
                transaction.Commit();
                return OtRegister.OTRegisterId;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public async Task<int> CancelAsync(OTRegisterInsertModel model)
        {
            var returnOTAppointment = await this.unitOfWork.OTRegisters.FindAsync(m => m.OTRegisterId == model.OTRegisterId);
            if (returnOTAppointment == null)
            {
                return -1;
            }
            returnOTAppointment.Active = false;
            returnOTAppointment.Status = 'C'.ToString();
            returnOTAppointment.Reason = model.Reason;
            returnOTAppointment.ModifiedBy = model.ModifiedBy;
            returnOTAppointment.ModifiedDate = DateTime.Now;
            returnOTAppointment.OTRegisterId = await this.unitOfWork.OTRegisters.UpdateAsync(returnOTAppointment);  
            return returnOTAppointment.OTRegisterId;
        }
        public async Task<int> RescheduleAsync(int otRegisterId, int modifiedBy, DateTime appointmentDate, DateTime appointmentEndTime, int otRoomId)
        {
            var appointment = await this.unitOfWork.OTRegisters.FindAsync(m => m.OTRegisterId == otRegisterId);
            appointment.OTRoomId = otRoomId;
            appointment.ModifiedDate = DateTime.UtcNow;
            appointment.ModifiedBy = modifiedBy;
            appointment.OldAppointmentDate = appointment.SignInDate;
            appointment.SignInDate = appointmentDate;  //date and time           
            appointment.SignOutDate =  appointmentEndTime;
            appointment.ShiftWardToDate = appointmentEndTime;
            appointment.Status = "R";
            return await this.unitOfWork.OTRegisters.UpdateAsync(appointment);
        }
        /// <summary>
        /// the update async
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<int> UpdateAsync(OTRegisterInsertModel model)
        {            
                var availability = await this.unitOfWork.OTRegisters.FindAsync(m => m.OTRegisterId == model.OTRegisterId);

                if (availability == null)
                {
                    return -1;
                }
                var query = $@"Delete from ""OTRegister"" where ""OTRegisterId"" = {availability.OTRegisterId}";
                int executedStatues = await this.unitOfWork.Current.ExecuteAsync(query);
                if (executedStatues <= 0)
                {
                    return -1;
                }
                var OtRegister = new OTRegister
                {
                    OTRegisterId = model.OTRegisterId,
                    PatientId = model.PatientId,
                    ProviderId = model.ProviderId,
                    //AssitantId = model.AssitantId,
                    //AnaesthetistId = model.AnaesthetistId,
                    //AnaesthesiaTypeId = model.AnaesthesiaTypeId,
                    //NurseId = model.NurseId,
                    SurgeryId = model.SurgeryId,
                    //SurgeryTypeId = model.SurgeryTypeId,
                    //Diagnosis = model.Diagnosis,
                    //Remarks = model.Remarks,
                    OREntryDate = model.OREntryDate,
                    SignInDate = model.SignInDate,
                    SignOutDate = model.SignOutDate,
                    ShiftWardToDate = model.ShiftWardToDate,
                    //CaseTypeId = model.CaseTypeId,                    
                    Active = true,
                      CreatedBy = model.CreatedBy,
                     CreatedDate = DateTime.Now,
                    ModifiedBy = model.CreatedBy,
                    ModifiedDate = DateTime.Now,
                    OTRoomId=model.OTRoomId
                };
                return await this.unitOfWork.OTRegisters.InsertAsync(OtRegister);
           
        }

        /// <inheritdoc />
        public Task<int> DeleteAsync(int? otRegisterId)
        {
            var query = $@"DELETE FROM ""OTRegister"" WHERE ""OTRegisterId""= {otRegisterId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }       
        public async Task<string> FetchAltAsync(int OTRegisterId)
        {
            var query = $@"select ot.""RoomName"",otr.* from ""OTRegister"" otr
left join ""OTRoom"" ot on ot.""OTRoomId""=otr.""OTRoomId""
where otr.""OTRegisterId""={OTRegisterId}";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
        }

        public async Task<IEnumerable<OTRegisterFilterModel>> FetchFilterEvent(OTFilterModel model)
        {
            var where = " Where 1=1";
            if (!string.IsNullOrEmpty(model.Filter[0].FromDate))
            {
                where += $@" AND a.""SignInDate""::DATE = '%{model.Filter[0].FromDate}%'";
            }
            if (model.Filter[0].PatientId != null)
            {
                where += $@" AND a.""PatientId"" = {model.Filter[0].PatientId}";
            }
            if (model.Filter[0].PatientName != null)
            {
                where += $@" AND a.""PatientName"" = {model.Filter[0].PatientName}";
            }
            if (model.SurgeryId != null)
            {
                where += $@" AND st.""SurgeryId"" = {model.SurgeryId}";
            }
            if (!string.IsNullOrEmpty(model.OTRoomId))
            {
                where += $@"  and  a.""OTRoomId"" in ({model.OTRoomId})";
            }
            
            var query = $@" select a.""OTRegisterId"",a.""Status"",a.""PatientId"",p.""FullName"" as ""Patient"",st.""SurgeryId"", a.""OTRoomId"",a.""SignInDate""::text,a.""SignOutDate""::text,s.""RoomName""
                    from ""OTRegister"" a
                            left Join ""OTRoom"" s on s.""OTRoomId"" = a.""OTRoomId""
                            left Join ""Surgery"" st on st.""SurgeryId"" = a.""SurgeryId""
                            left join ""Patient"" p on P.""PatientId"" = a.""PatientId""            
                            {where} and a.""Status"" !='C'";
            return await this.unitOfWork.Current.QueryAsync<OTRegisterFilterModel>(query);
        }
    }

}
