namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Configurations;
    using Domain.Entities;
    using Domain.Helpers;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.Library.Enums;
    using Shared.UserModels;
    using Shared.UserModels.Filters;
    using Shared.UserModels.Common;
    using Hims.Shared.UserModels.ChargeManagement;
    using Hims.Domain.Entities.Enums;
    using System.Text;
    using System.Security.Cryptography;
    using System.Net;
    using static System.Net.Mime.MediaTypeNames;
    using System.Net.NetworkInformation;
    using System.Buffers.Text;
    using System.Transactions;
    using System.Text.RegularExpressions;
    using Hims.Shared.UserModels.Labs;
    using Hims.Shared.UserModels.Scan.ScanAppointment;
    using System.Reflection;
    using Hims.Shared.Library;

    /// <inheritdoc />
    public class PatientServices : IPatientService
    {
        /// <summary>
        /// the unit of work
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// The amazon s 3 configuration.
        /// </summary>
        private readonly IAmazonS3Configuration amazonS3Configuration;


        /// <summary>
        /// The sha helper.
        /// </summary>
        private readonly IShaHelper shaHelper;

        /// <summary>
        /// the wallet service
        /// </summary>
        private readonly IWalletService walletServices;

        /// <summary>
        /// The helper.
        /// </summary>
        private readonly IDocumentHelper documentHelper;
        /// <summary>
        /// The appointment transaction services.
        /// </summary>
        private readonly IAppointmentTransactionService appointmentTransactionsServices;

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

        /// <summary>
        /// The payment map helper service
        /// </summary>
        private readonly IPaymentMapHelperService paymentMapHelperService;
        /// <summary>
        /// The payment map helper service
        /// </summary>
        private readonly ILabTransactionService labTransactionService;
        ///// <summary>
        ///// The payment map helper service
        ///// </summary>
        //private readonly IBookScanAppointmentService bookScanAppointmentService;

        /// <inheritdoc cref="IPatientService" />
        public PatientServices(IUnitOfWork unitOfWork, IShaHelper shaHelper, IAmazonS3Configuration amazonS3Configuration, IWalletService walletServices, IDocumentHelper documentHelper, IAppointmentTransactionService appointmentTransactionsServices, IRunningEnvironment runningEnvironment, IPaymentMapHelperService paymentMapHelperService, ILabTransactionService labTransactionService)
        {
            this.unitOfWork = unitOfWork;
            this.shaHelper = shaHelper;
            this.amazonS3Configuration = amazonS3Configuration;
            this.walletServices = walletServices;

            this.documentHelper = documentHelper;
            this.appointmentTransactionsServices = appointmentTransactionsServices;
            this.runningEnvironment = runningEnvironment;
            this.paymentMapHelperService = paymentMapHelperService;
            this.labTransactionService = labTransactionService;
            //this.bookScanAppointmentService = bookScanAppointmentService;
        }

        /// <inheritdoc />
        public async Task<int> RegisterAsync(PatientRegistrationModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var patient = new Patient
                {
                    Active = true,
                    CreatedBy = null,
                    CreatedDate = DateTime.Now,
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    FullName = CoreFilter.FullName(model.FirstName, string.Empty, model.LastName),
                    UMRNo = await this.GetLatestUMRNo(),
                    Guid = Guid.NewGuid()
                };

                if (model.CountryId == null && model.Username.Contains("@"))
                {
                    patient.Email = model.Username;
                }
                else
                {
                    patient.Mobile = model.Username;
                    patient.CountryId = Convert.ToInt32(model.CountryId);
                }

                patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);
                if (patient.PatientId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == patient.Email && m.Mobile == patient.Mobile && m.CountryId == model.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId > 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                var account = new Account
                {
                    RoleId = (int)Roles.Patient,
                    ReferenceId = patient.PatientId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.UtcNow,
                    FullName = patient.FullName,
                    CountryId = patient.CountryId,
                    Mobile = patient.Mobile,
                    Email = patient.Email,
                    AgreedDate = model.IsAgreed ? DateTime.UtcNow : (DateTime?)null,
                    Active = true,
                    OTPVerified = true,
                    Guid = patient.Guid
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (!string.IsNullOrEmpty(model.Password))
                {
                    var passwordHash = this.shaHelper.GenerateHash(model.Password, account.SaltKey);
                    var query = new AccountsCredential(account, passwordHash).Query;

                    var inserted = await this.unitOfWork.Current.ExecuteAsync(query, transaction);
                    if (inserted == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }

                transaction.Commit();
                return account.AccountId;
            }
        }

        /// <inheritdoc />
        public async Task<int> RegisterWithOutOtpAsync(PatientRegistrationModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var patient = new Patient
                {
                    Active = true,
                    CreatedBy = null,
                    CreatedDate = DateTime.UtcNow,
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    FullName = !string.IsNullOrEmpty(model.FirstName) ? CoreFilter.FullName(model.FirstName, string.Empty, model.LastName) : string.Empty,
                    UMRNo = model.Username,
                    Guid = Guid.NewGuid(),
                    PaymentStatus = false,
                    TempPatient = true
                };

                if (model.CountryId == null && model.Username.Contains("@"))
                {
                    patient.Email = model.Username;
                }
                else
                {
                    patient.Mobile = model.Username;
                    patient.CountryId = Convert.ToInt32(model.CountryId);
                }

                patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);
                if (patient.PatientId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == patient.Email && m.Mobile == patient.Mobile && m.CountryId == model.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId > 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                var account = new Account
                {
                    RoleId = (int)Roles.Patient,
                    ReferenceId = patient.PatientId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.UtcNow,
                    FullName = patient.FullName,
                    CountryId = patient.CountryId,
                    Mobile = patient.Mobile,
                    Email = patient.Email,
                    AgreedDate = model.IsAgreed ? DateTime.UtcNow : (DateTime?)null,
                    Active = true,
                    OTPVerified = false,
                    ManualVerified = false,
                    IsAgreed = false,
                    Guid = patient.Guid
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return account.AccountId;
            }
        }

        public async Task<Patient> GetRawAsync(int patientId)
        {
            return await this.unitOfWork.Patients.FindAsync(x => x.PatientId == patientId);
        }

        /// <inheritdoc />
        public Task<PatientModel> FindAsync(int patientId)
        {
            var where = $@" WHERE pat.""PatientId"" = {patientId}";

            var query = $@"SELECT pat.""ReferredByNameId"",pf.""Education"" as ""RelativeEducation"",pf.""Occupation"" as ""RelativeOccupation"",ic.""FullName"" ""InsuranceCompany"",pt.""Breakfast"",pat.""InsuranceCompanyId"",ap.""OtherRemarks"",id.""IdProofName"",pat.""AddressLine2"" as ""Area"" ,pf.""FullName"" as ""RelativeName"",pf.""Relation"",referred.""PatientReferredById"",ap.""ProviderId"",pr.""FullName"" as ""ProviderName"",pr.""DepartmentId"",pt.""Lunch"", pt.""Dinner"", ds.""DischargeId"",ad.""AdmissionId"",pat.*, cun.""CountryName"", cun.""CountryCode"", cun.""ISOCode"",
                referred.""Name"" , referred.""Name"" as ""ReferredBy"",pat.""Salutation"",HWC.""HWCName"",eid.""Name"" as ""EducationName"",hid.""Name"" as ""HowDidYouKnow"",oid.""Name"" as ""OccupationName"",
                        cra.""FullName"" AS ""CreatedByName"", mdf.""FullName"" AS ""ModifiedByName"",
                         (CASE WHEN pat.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}','/', pat.""Guid"", '/', pat.""ProfileImageUrl"") ELSE '' END) AS ""ProfileImageUrl"",
                         (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl"",
                        pat.""RelationType"",pat.""OccupationDetail"",pat.""Guid""
                        FROM ""Patient"" pat
                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = pat.""CountryId"" AND cun.""Active"" IS TRUE
                         LEFT JOIN ""PatientReferredBy"" referred ON referred.""PatientReferredById"" = pat.""PatientReferredById""
                        LEFT JOIN ""Account"" cra ON cra.""AccountId"" = pat.""CreatedBy"" AND cra.""Active"" IS TRUE
                        LEFT JOIN ""Account"" mdf ON mdf.""AccountId"" = pat.""ModifiedBy"" AND mdf.""Active"" IS TRUE 
                        LEFT JOIN ""Admission"" ad ON ad.""PatientId"" = pat.""PatientId"" AND ad.""Active"" IS TRUE 
						left join ""Appointment"" ap on ap.""PatientId"" = pat.""PatientId"" and ap.""Active"" is true
                         LEFT JOIN ""Provider"" pr on pr.""ProviderId"" = ap.""ProviderId""
                        LEFT JOIN ""PatientTiming"" pt on pt.""PatientId"" = pat.""PatientId"" 
                        left join ""Discharge"" ds on ds.""AdmissionId"" = ad.""AdmissionId"" and ds.""Active"" = true 
                        left join ""HWCPatient""  HWC on HWC.""HWCPatientId"" = pat.""HWCPatientId""
						left join ""IdProof"" id on id.""IdProofId"" = pat.""IdProofId""
                        left join ""HowDidYouKnow"" hid on hid.""HowDidYouKnowId"" = pat.""HowDidYouKnowId""
                        left join ""Education"" eid on eid.""EducationId"" = pat.""EducationId""
                        left join ""Occupation"" oid on oid.""OccupationId"" = pat.""OccupationId""
						left join ""PatientFamily"" pf on pf.""PatientId"" = pat.""PatientId""
                        left join ""InsuranceCompany"" ic on ic.""InsuranceCompanyId"" = pat.""InsuranceCompanyId""
                        {where}";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<PatientModel>(query);
        }


        public Task<IEnumerable<PatientFamilyModel>> FetchPatientFamilyAsync(int patientId)
        {
            var query = $@"SELECT  ""PatientFamilyId"",""PatientId"", ""FullName"", ""Relation"", ""Age"", ""Gender"" ""RelativeGender"", ""Active"", ""CreatedBy"", ""CreatedDate"", ""ModifiedBy"", ""ModifiedDate"", ""ContactNo"", ""Education"", ""Occupation"", ""DOB"", ""OccupationDetails"",""BloodGroup"" ""RelativeBloodGroup""  FROM ""PatientFamily"" WHERE ""PatientId"" = {patientId}";
            //var where = $@" WHERE ""PatientId"" = {patientId}";
            //** /*var query =*/ $@"SELEC*/T patins.*,IC.""FullName"" AS ""InsuranceCompanyName"" FROM ""PatientInsurance"" patins JOIN ""InsuranceCompany"" IC ON IC.""InsuranceCompanyId"" = patins.""InsuranceCompanyId"" {where} ORDER BY patins.""PatientInsuranceId"" DESC";*/
            return this.unitOfWork.Current.QueryAsync<PatientFamilyModel>(query);
        }
        public Task<int> FetchPatientFamilyIdAsync(int patientId)
        {
            var query = $@"SELECT  ""PatientFamilyId"" FROM ""PatientFamily"" WHERE ""PatientId"" = {patientId}";
            //var where = $@" WHERE ""PatientId"" = {patientId}";
            //** /*var query =*/ $@"SELEC*/T patins.*,IC.""FullName"" AS ""InsuranceCompanyName"" FROM ""PatientInsurance"" patins JOIN ""InsuranceCompany"" IC ON IC.""InsuranceCompanyId"" = patins.""InsuranceCompanyId"" {where} ORDER BY patins.""PatientInsuranceId"" DESC";*/
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query);
        }
        /// <inheritdoc />
        public Task<PatientModel> FindAsync(Guid guid)
        {
            var where = $@" WHERE pat.""Active"" IS TRUE AND pat.""Guid"" = '{guid}'";
            var query = $@"SELECT pat.*  FROM ""Patient"" pat{where}";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<PatientModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PatientModel>> FetchAsync(PatientFilterModel model)
        {
            var where = @"WHERE 1 = 1 ";
            if (model.PatientId > 0)
            {
                where += $@" AND pat.""PatientId"" = {model.PatientId} ";
            }
            if (model.HWCPatientId > 0)
            {
                where += $@" AND HWC.""HWCPatientId"" = {model.HWCPatientId} ";
            }
            if (model.LocationId > 0)
            {
                where += $@" AND l.""LocationId"" = {model.LocationId} ";
            }
            if (!string.IsNullOrEmpty(model.FullName))
            {
                where += $@" AND pat.""FullName"" ILIKE '%{model.FullName}%' ";
            }

            if (!string.IsNullOrEmpty(model.Email))
            {
                where += $@" AND pat.""Email"" ILIKE '%{model.Email}%' ";
            }

            if (!string.IsNullOrEmpty(model.Mobile))
            {
                where += $@" AND pat.""Mobile"" ILIKE '%{model.Mobile}%' ";
            }

            if (!string.IsNullOrEmpty(model.UMRNo))
            {
                where += $@" AND pat.""UMRNo"" ILIKE '%{model.UMRNo}%' ";
            }

            if (model.Gender != null)
            {
                where += $@" AND pat.""Gender"" = '{model.Gender}' ";
            }

            if (model.CountryId != null)
            {
                where += $@" AND pat.""CountryId"" = '{model.CountryId}' ";
            }

            if (model.Active != null)
            {
                where += $@" AND pat.""Active"" IS {((bool)model.Active ? "TRUE" : "FALSE")} ";
            }

            if (!string.IsNullOrEmpty(model.CreatedDate))
            {
                where += $@" AND pat.""CreatedDate""::DATE = '{model.CreatedDate}'::DATE ";
            }

            if (model.Active != null)
            {
                where += $@" AND pat.""Active"" IS {((bool)model.Active ? "TRUE" : "FALSE")} ";
            }

            var query = $@"SELECT Count(*) OVER() AS ""TotalItems"" ,* from (Select distinct l.""LocationId"", l.""NameLoc"" ""LocationName"", pat.""PatientId"", pat.""Guid"", pat.""ReferralCode"", act.""AccountId"", pat.""Salutation"", pat.""FullName"", pat.""FatherOrHusband"",
                                pat.""UMRNo"", pat.""Gender"", pat.""DateOfBirth"", pat.""Age"", pat.""CountryId"", pat.""Email"", pat.""Mobile"", pat.""Active"", pat.""CreatedDate"",pat.""BloodGroup"",pat.""PaymentStatus"",
                               pat.""BirthMark1"",pat.""BirthMark2"",pat.""ParentPatientId"",
                                pat.""PaymentNumber"", pat.""PayTypeId"",HWC.""HWCName"",HWC.""HWCPatientId"",HWC.""Description"",HWC.""RowColor"",
                                (CASE WHEN pat.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}','/', pat.""Guid"", '/', pat.""ProfileImageUrl"") ELSE '' END) AS ""ProfileImageUrl"",
                         (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl"",
                                ctr.""CountryName"", ctr.""CountryCode"", ctr.""ISOCode"", crt.""FullName"" AS ""CreatedByName"", act.""IsLocked"", act.""OTPVerified"", act.""ManualVerified""
                                ,CASE WHEN acs.""AccountSessionId"" IS NULL THEN FALSE ELSE TRUE END AS ""IsOnline""
                            ,CASE WHEN pat.""REGNO""::text IS NULL THEN NULL ELSE pat.""REGNO""::text END 
                                FROM ""Patient"" pat
                                JOIN ""Account"" act ON act.""ReferenceId"" = pat.""PatientId"" AND act.""RoleId"" = '{(int)Roles.Patient}'
                                left JOIN ""LocationAccountMap"" la on la.""AccountId"" = act.""AccountId""
                                left JOIN ""Location"" l on l.""LocationId"" = la.""LocationId""
                                LEFT JOIN ""Account"" crt ON crt.""AccountId"" = pat.""CreatedBy"" AND crt.""Active"" IS TRUE
                                LEFT JOIN ""Country"" ctr ON ctr.""CountryId"" = pat.""CountryId"" AND ctr.""Active"" IS TRUE
                                left join ""AccountSession"" acs on acs.""AccountId"" = act.""AccountId""  AND acs.""Active"" IS TRUE 
                                left join ""HWCPatient""  HWC on HWC.""HWCPatientId"" = pat.""HWCPatientId""
                                {where}
                                ORDER BY pat.""PatientId"" DESC) A";

            if (model.ProviderId != null)
            {
                where += $@" AND pat.""Active"" IS TRUE AND (A.""ProviderId"" = {model.ProviderId} OR Adm.""ProviderId"" = {model.ProviderId}  OR pat.""CreatedBy"" = (Select ""Account"".""AccountId"" FROM ""Account"" WHERE ""Account"".""ReferenceId"" = {model.ProviderId} AND ""Account"".""RoleId"" = {(int)Roles.Provider})) ";

                query = $@"SELECT Count(A.""PatientId"") OVER() AS ""TotalItems"",A.* FROM (SELECT DISTINCT pat.""PatientId"", pat.""Salutation"", pat.""FullName"", pat.""FatherOrHusband"", pat.""DateOfBirth"", pat.""Age"", pat.""Gender"", pat.""CreatedDate"",
                                pat.""UMRNo"", pat.""Email"", pat.""Mobile"", pat.""CountryId"", pat.""Active"", pat.""ReferralCode"",pat.""PaymentStatus"", pat.""PaymentNumber"", pat.""PayTypeId"",
                                HWC.""HWCName"",HWC.""HWCPatientId"",HWC.""Description"",HWC.""RowColor"",
                                (CASE WHEN pat.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}','/', pat.""Guid"", '/', pat.""ProfileImageUrl"") ELSE '' END) AS ""ProfileImageUrl"",
                                (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl"",
                                C.""CountryName"", C.""CountryCode"", C.""ISOCode"", ACT.""AccountId"", pat.""Guid"", crt.""FullName"" AS ""CreatedByName"", act.""IsLocked"", act.""OTPVerified"", act.""ManualVerified"" 
                                FROM ""Patient"" pat
                                LEFT JOIN ""Country"" C on C.""CountryId"" = pat.""CountryId"" AND C.""Active"" IS TRUE
                                LEFT JOIN ""Account"" ACT on ACT.""ReferenceId"" = pat.""PatientId"" AND ACT.""RoleId"" = {(int)Roles.Patient} AND ACT.""Active"" IS TRUE
                                LEFT JOIN ""Account"" crt ON crt.""AccountId"" = pat.""CreatedBy"" AND crt.""Active"" IS TRUE
                                LEFT JOIN ""Appointment"" A on A.""PatientId"" = pat.""PatientId"" 
                                left join ""Admission"" Adm on Adm.""PatientId"" = pat.""PatientId""
                                left join ""HWCPatient""  HWC on HWC.""HWCPatientId"" = pat.""HWCPatientId""
                                {where} ) A
                                Order by A.""PatientId"" DESC";
            }

            if (model.PageIndex <= 0)
            {
                return await this.unitOfWork.Current.QueryAsync<PatientModel>(query);
            }

            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}";
            }
            //  query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            var patientModels = await this.unitOfWork.Current.QueryAsync<PatientModel>(query);
            return patientModels;


        }

        /// <inheritdoc />
        public Task<IEnumerable<PatientModel>> FetchExistingPatientsAsync(PatientModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += !string.IsNullOrEmpty(model.Mobile) ? $@",'{model.Mobile}'" : ",null";
            //parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo.Trim()}'" : ",null";            
            parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo}'" : ",null";
            parameters += !string.IsNullOrEmpty(model.FullName) ? $@",'{model.FullName.Trim()}'" : ",null";
            //parameters += !string.IsNullOrEmpty(model.BillNumber) ? $@",'{model.BillNumber}'" : ",null";


            var query = $@"select * from ""udf_FetchPatientsFilter_For_Appointment""({parameters})";

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

        /// <inheritdoc />
        public Task<AppointmentModel> CheckForFollowUpForPatientAsync(AppointmentModel model)
        {
            var query = $@"select *,  sum(A.""FreeVisitsCountCheck"") over (partition by A.""VisitTypeId"") as ""FreeVisitsCount"" from (
                                select DSM.""FollowUpDays"" as ""FreeFollowUpDays"",  DSM.""FollowUpDaysLimit"" as ""FreeFollowUpDaysLimit"" ,CMT.""StartDate"",CMT.""EndDate""
	--,pl.""StartTime"",pl.""EndTime"",
	                                ,ap.*,
								(select count(VT.""VisitTypeId"")  from ""VisitType"" VT where VT.""VisitTypeId"" = ap.""VisitTypeId"" and trim(VT.""VisitorName"")
								 ILIKE '%FOLLOW%') as ""FreeVisitsCountCheck""
								
                                from ""Appointment"" ap
                                join ""DoctorSpecializationChargeModuleDetails"" pl on pl.""DoctorSpecializationChargeModuleDetailsId"" = ap.""DoctorSpecializationChargeModuleDetailsId""
                                Join ""DoctorSpecializationMap"" DSM on DSM.""DoctorSpecializationMapId"" = pl.""ReferenceId""
                                Join ""DoctorSpecializationChargeModuleCategory"" DSC on DSC.""DoctorSpecializationChargeModuleCategoryId"" = pl.""DoctorSpecializationChargeModuleCategoryId"" and DSC.""Active"" is true
                                JOIN ""ChargeModuleTemplate"" CMT ON CMT.""ChargeModuleTemplateId"" = DSC.""ChargeModuleTemplateId"" and CMT.""IsInUse"" is true
                                where ap.""PatientId""= {model.PatientId} 
                                and ap.""ProviderId"" = {model.ProviderId} 
                                and ap.""SpecializationId"" = {model.SpecializationId}
                                and ap.""LocationId"" = {model.LocationId}
                                and ap.""ConsultationTypeId"" = {model.ConsultationTypeId}
                                and ap.""Status"" <> 'C' 
                                and ap.""PaymentStatus"" is true
                                --and ap.""AppointmentDate"" <= now()
                                and  (ap.""AppointmentDate""::date >= CMT.""StartDate""::date AND ap.""AppointmentDate""::date <= CMT.""EndDate""::date)
                                --and  (ap.""AppointmentTime""::time without time zone >= CMT.""StartTime""::time without time zone AND ap.""AppointmentTime""::time without time zone <= pl.""EndTime""::time without time zone)
                                 and ap.""VisitTypeId"" not in (11)) as A
                                order by A.""AppointmentId"" desc 
	
	                                limit 1";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AppointmentModel>(query);
        }

        public async Task<Tuple<int, int, Guid?>> AddAsync(PatientModel model, List<PatientEmergencyModel> patientEmergencies, List<PatientInsuranceModel> patientInsurances, PatientFamilyModel pfModel, List<PatientFamilyModel> patientFamilyModel)
        {
            try
            {
                //master/add pat
                var billId = 0;
                var secondBillId = 0;
                using (var transaction = this.unitOfWork.BeginTransaction())
                {
                    var checkIf = await this.CheckPatientAsync(model.Mobile, model.CountryId, model.Email, model.PatientId);
                    if (checkIf != 0)
                    {
                        //transaction.Rollback();
                        //return new Tuple<int, int, Guid?>(checkIf, checkIf, null);
                    }
                    if (model.PaymentStatus != true)
                    {
                        var checkUMRNo = await this.CheckPatientUMRNo(model.Mobile);
                        if (checkUMRNo != 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(checkUMRNo, checkUMRNo, null);

                        }
                    }

                    var umrNo = "";
                    if (!string.IsNullOrEmpty(model.REGNO))
                    {
                        umrNo = model.REGNO;
                    }
                    else
                    {
                        umrNo = model.PaymentStatus == true ? await this.GetLatestUMRNo() : model.Mobile;
                    }

                    decimal? amount = 0;
                    double? Total = 0;
                    decimal? DiscountInPercentage = 0;
                    decimal? DiscountInRupees = 0;
                    model.Amount = model.Amount != null ? model.Amount : 0;
                    if (model.SaveRelativeAsPatient == true)
                    {
                        amount = model.Amount != null && model.Amount > 0 ? model.Amount / 2 : model.Amount;
                        Total = model.Total > 0 ? model.Total / 2 : model.Total;
                        DiscountInPercentage = Math.Round(model.DiscountInPercentage, 2);
                        DiscountInRupees = DiscountInPercentage > 0 ? Math.Round((((decimal)amount * (decimal)DiscountInPercentage) / 100), 2) : 0;
                        Total = DiscountInRupees > 0 ? (double)amount - (double)DiscountInRupees : Total;
                    }
                    else
                    {
                        amount = model.Amount;
                        Total = model.Total;
                        DiscountInPercentage = model.DiscountInPercentage;
                        DiscountInRupees = model.DiscountInRupees;
                    }

                    // Patient
                    var patient = new Patient
                    {
                        Active = true,
                        Salutation = model.Salutation,
                        FirstName = model.FirstName,
                        MiddleName = model.MiddleName,
                        LastName = model.LastName,
                        AadharNo = model.AadharNo,
                        FullName = model.FullName,
                        FatherOrHusband = model.FatherOrHusband,
                        UMRNo = umrNo,
                        TempPatient = model.PaymentStatus != true ? true : false,
                        DateOfBirth = model.DateOfBirth,
                        Age = model.Age,
                        Gender = model.Gender,
                        MaritalStatus = model.MaritalStatus,
                        Email = model.Email,
                        Mobile = model.Mobile,
                        StreetAddress = model.StreetAddress,
                        AddressLine2 = model.AddressLine2,
                        City = model.City,
                        State = model.State,
                        Zipcode = model.Zipcode,
                        CountryId = model.CountryId,
                        //ProfileImageUrl = model.ProfileImageUrl,
                        //ThumbnailUrl = model.ThumbnailUrl,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.UtcNow,
                        Guid = Guid.NewGuid(),
                        // ReferredBy = model.ReferredBy,
                        PatientReferredById = model.PatientReferredById,
                        ReferredByName = model.ReferredByName,
                        LocationId = model.LocationId,
                        HWCPatientId = model.HWCPatientId,
                        Education = model.Education,
                        Occupation = model.Occupation,
                        Nationality = model.Nationality,
                        Religion = model.Religion,
                        IdProofId = model.IdProofId,
                        IdProofValue = model.IdProofValue,
                        BloodGroup = model.BloodGroup,
                        //Amount = model.PaymentStatus == true ? model.Charges : 0,
                        PaymentNumber = model.PaymentNumber,
                        PaymentStatus = model.PaymentStatus,
                        PayTypeId = model.PaymentStatus == true ? model.PayTypeId : null,
                        HowDidYouKnowId = model.HowDidYouKnowId,
                        EducationId = model.EducationId,
                        OccupationId = model.OccupationId,
                        BirthMark1 = model.BirthMark1,
                        BirthMark2 = model.BirthMark2,
                        //RelationType = model.RelationType,
                        OccupationDetail = model.OccupationDetail,
                        IsNewPatient = true,
                        InsuranceCompanyId = model.InsuranceId,
                        ReferredByNameId = model.ReferredByNameId,
                        REGNO = model.REGNO,
                        Amount = model.PaymentStatus == true ? amount : 0,
                        Total = (decimal)Total,
                        DiscountInPercentage = DiscountInPercentage,
                        DiscountInRupees = DiscountInRupees// ??
                    };
                    patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);

                    //if (patient.REGNO != null && patient.REGNO !="")
                    //{
                    //    var query = $@"UPDATE ""Patient"" SET ""UMRNo""='{ patient.REGNO}' WHERE ""PatientId""= {patient.PatientId}";
                    //     var result= await this.unitOfWork.Current.ExecuteAsync(query);    
                    //}

                    if (patient.PatientId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, int, Guid?>(checkIf, checkIf, null);
                    }
                    var relativeAsPatient = new Patient();
                    //Patient Relative Details
                    if (patientFamilyModel.Any())
                    {
                        var completed = 0;
                        foreach (var patientFamily in patientFamilyModel.Select(item => new PatientFamily
                        {

                            PatientId = patient.PatientId,
                            FullName = item.FullName,
                            Relation = item.Relation,
                            Age = item.Age != null ? (int)item.Age : 0,
                            Gender = item.RelativeGender,
                            Active = true,
                            CreatedBy = Convert.ToInt32(model.CreatedBy),
                            CreatedDate = DateTime.UtcNow,
                            ContactNo = item.ContactNo,
                            Education = item.Education,
                            Occupation = item.Occupation,
                            DOB = item.DOB,
                            OccupationDetails = item.OccupationDetails,
                            BloodGroup = item.RelativeBloodGroup
                        }
                    ))
                        {
                            patientFamily.PatientFamilyId = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                            if (patientFamily.PatientFamilyId != 0)
                            {
                                if (model.SaveRelativeAsPatient == true)
                                {
                                    // Patient
                                    relativeAsPatient = new Patient
                                    {
                                        Active = true,
                                        FirstName = patientFamily.FullName,
                                        LastName = ".",
                                        FullName = patientFamily.FullName,
                                        UMRNo = model.PaymentStatus == true ? await this.GetLatestUMRNo() : patientFamily.ContactNo,
                                        TempPatient = model.PaymentStatus != true ? true : false,
                                        DateOfBirth = patientFamily.DOB,
                                        Age = (short)patientFamily.Age,
                                        Gender = patientFamily.Gender,
                                        CountryId = model.CountryId,
                                        Amount = model.PaymentStatus == true ? amount : 0,
                                        PaymentNumber = model.PaymentNumber,
                                        PaymentStatus = model.PaymentStatus,
                                        PayTypeId = model.PaymentStatus == true ? model.PayTypeId : null,
                                        Mobile = patientFamily.ContactNo,
                                        CreatedBy = model.CreatedBy,
                                        CreatedDate = DateTime.UtcNow,
                                        Guid = Guid.NewGuid(),
                                        Education = patientFamily.Education,
                                        Occupation = patientFamily.Occupation,
                                        Nationality = model.Nationality,
                                        OccupationDetail = patientFamily.OccupationDetails,
                                        BloodGroup = patientFamily.BloodGroup,
                                        IsNewPatient = true,
                                        Total = (decimal)Total,
                                        DiscountInPercentage = DiscountInPercentage,
                                        LocationId = model.LocationId,
                                        DiscountInRupees = DiscountInRupees// ??
                                    };
                                    relativeAsPatient.PatientId = await this.unitOfWork.Patients.InsertAsync(relativeAsPatient, transaction);

                                    // Patient's Account
                                    var relativeSaltKey = CoreFilter.Random(10);
                                    var relativeExistingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Mobile == patientFamily.ContactNo && m.CountryId == model.CountryId, transaction);
                                    if (relativeExistingAccount != null && relativeExistingAccount.AccountId > 0)
                                    {
                                        relativeSaltKey = relativeExistingAccount.SaltKey;
                                    }

                                    // Account
                                    var relativeAccount = new Account
                                    {
                                        RoleId = (int)Roles.Patient,
                                        ReferenceId = relativeAsPatient.PatientId,
                                        SaltKey = relativeSaltKey,
                                        CreatedDate = DateTime.UtcNow,
                                        FullName = relativeAsPatient.FullName,
                                        CountryId = patient.CountryId,
                                        Mobile = patientFamily.ContactNo,
                                        //Email = patient.Email,
                                        Active = true,
                                        Guid = relativeAsPatient.Guid,
                                        IsAgreed = false
                                    };

                                    relativeAccount.AccountId = await this.unitOfWork.Accounts.InsertAsync(relativeAccount, transaction);
                                    if (relativeAccount.AccountId == 0)
                                    {
                                        transaction.Rollback();
                                        return new Tuple<int, int, Guid?>(0, checkIf, null);
                                    }
                                    // Location
                                    var relativeLocation = new LocationAccountMap
                                    {
                                        AccountId = relativeAccount.AccountId,
                                        LocationId = model.LocationId
                                    };
                                    var relativeLocationId = await this.unitOfWork.LocationAccountMap.InsertAsync(relativeLocation, transaction);
                                    if (relativeLocationId == 0)
                                    {
                                        transaction.Rollback();
                                        return new Tuple<int, int, Guid?>(0, checkIf, null);
                                    }
                                }
                                completed++;
                            }
                        }
                        if (completed != patientFamilyModel.Count)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }
                    }

                    // Patient Emergency Contacts
                    if (patientEmergencies.Any())
                    {
                        var inserted = 0;
                        foreach (var patientEmergency in patientEmergencies.Select(item => new PatientEmergency
                        {
                            Active = true,
                            CreatedDate = DateTime.UtcNow,
                            CreatedBy = Convert.ToInt32(model.CreatedBy),
                            PatientId = patient.PatientId,
                            Address = item.Address,
                            FullName = item.FullName,
                            Mobile = item.Mobile,
                            Relation = item.Relation
                        }))
                        {
                            patientEmergency.PatientEmergencyId = await this.unitOfWork.PatientEmergencies.InsertAsync(patientEmergency, transaction);
                            if (patientEmergency.PatientEmergencyId != 0)
                            {
                                inserted++;
                            }
                        }

                        if (inserted != patientEmergencies.Count)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }
                    }

                    // Patient Insurances
                    if (patientInsurances.Any())
                    {
                        var inserted = 0;
                        foreach (var patientInsurance in patientInsurances.Select(item => new PatientInsurance
                        {
                            Active = true,
                            CreatedDate = DateTime.UtcNow,
                            CreatedBy = Convert.ToInt32(model.CreatedBy),
                            PatientId = patient.PatientId,
                            InsuranceCompanyId = (int)item.InsuranceCompanyId,
                            CardNo = item.CardNo,
                            //                        Validity = item.Validity,

                            Validity = (DateTime)item.Validity,
                            InsuranceTypeId = (int)item.InsuranceTypeId
                        }))
                        {
                            patientInsurance.PatientInsuranceId = await this.unitOfWork.PatientInsurances.InsertAsync(patientInsurance, transaction);
                            if (patientInsurance.PatientInsuranceId != 0)
                            {
                                inserted++;
                            }
                        }

                        if (inserted != patientInsurances.Count)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }
                    }

                    // Patient's Account
                    var saltKey = CoreFilter.Random(10);
                    var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == model.Email && m.Mobile == model.Mobile && m.CountryId == model.CountryId, transaction);
                    if (existingAccount != null && existingAccount.AccountId > 0)
                    {
                        saltKey = existingAccount.SaltKey;
                    }

                    // Account
                    var account = new Account
                    {
                        RoleId = (int)Roles.Patient,
                        ReferenceId = patient.PatientId,
                        SaltKey = saltKey,
                        CreatedDate = DateTime.UtcNow,
                        FullName = patient.FullName,
                        CountryId = patient.CountryId,
                        Email = patient.Email,
                        Mobile = patient.Mobile,
                        Active = true,
                        Guid = patient.Guid,
                        IsAgreed = false
                    };

                    account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                    if (account.AccountId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, int, Guid?>(0, checkIf, null);
                    }
                    // Location
                    var location = new LocationAccountMap
                    {
                        AccountId = account.AccountId,
                        LocationId = model.LocationId
                    };
                    var locationId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                    if (locationId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, int, Guid?>(0, checkIf, null);
                    }

                    //var getRegistrationCharge = await this.unitOfWork.PatientRegistrationCharges.FindAsync(x => x.Active && x.LocationId == patient.LocationId);

                    //if (getRegistrationCharge == null)
                    //{
                    //    transaction.Rollback();
                    //    return new Tuple<int, int, Guid?>(-2, checkIf, null);
                    //}

                    //begin-MasterBill
                    var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.PatientId == patient.PatientId && x.BillStatusTypeId == 2 && x.ReceiptAreaTypeId == (int)ReceiptAreaType.PatientRegistration && x.ModuleId == patient.PatientId); //need to check more

                    if (getbillrecord == null)
                    {
                        var onebill = new MasterBill
                        {
                            ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,//main module
                                                                                         //ModuleId = (int)ReceiptAreaType.Labs, //sub module
                            ModuleId = patient.PatientId, // module-main table id.
                            BillDate = DateTime.Now,
                            BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                            BillStatusTypeId = (int)BillStatusType.Not_Generated,
                            CreatedBy = (int)model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            Active = true,
                            PatientId = patient.PatientId,
                            Total = (double)amount,
                            Discount = (double)DiscountInRupees,
                            NetTotal = (double)Total,
                            Rounding = (int)Total - (double)Total,
                            LocationId = model.LocationId
                        };
                        onebill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(onebill, transaction);
                        billId = onebill.MasterBillId;
                        if (onebill.MasterBillId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }

                        if (model.SaveRelativeAsPatient == true)
                        {
                            var secondbill = new MasterBill
                            {
                                ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,//main module
                                                                                             //ModuleId = (int)ReceiptAreaType.Labs, //sub module
                                ModuleId = relativeAsPatient.PatientId, // module-main table id.
                                BillDate = DateTime.Now,
                                BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                                BillStatusTypeId = (int)BillStatusType.Not_Generated,
                                CreatedBy = (int)model.CreatedBy,
                                CreatedDate = DateTime.Now,
                                Active = true,
                                PatientId = relativeAsPatient.PatientId,
                                Total = (double)amount,
                                Discount = (double)DiscountInRupees,
                                NetTotal = (double)Total,
                                Rounding = (int)Total - (double)Total,
                                LocationId = model.LocationId
                            };
                            secondbill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(secondbill, transaction);
                            secondBillId = secondbill.MasterBillId;
                            if (secondbill.MasterBillId == 0)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }
                    }
                    //end-MasterBill
                    if (model.PaymentStatus == true)
                    {
                        //transaction for registration
                        var commonTransaction = new AppointmentTransaction
                        {
                            AppointmentId = patient.PatientId, // respective Id
                            Transaction = model.Transaction ?? "",
                            TransactionDate = DateTime.Now,
                            TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                            VoucherNumber = model.SalucroStatusCode == 1201 ? null : await this.appointmentTransactionsServices.GetVoucherNumber(),
                            BankReference = "",
                            BankCode = "",
                            Active = true,
                            PaymentId = 0,
                            PaymentModeId = 1,
                            SettledAmount = (decimal)Total,
                            CreatedBy = (int)model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            SalucroStatusCode = model.SalucroStatusCode,
                            SalucroTransactionId = model.SalucroTransactionId,
                            LocationId = model.LocationId,
                            ReceiptTypeId = (int)ReceiptType.Cash, // credit
                            ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,
                            PatientId = patient.PatientId,
                            PayStatus = 'F'
                        };
                        commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                        if (commonTransaction.AppointmentTransactionId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }

                        var commonTransactionForRelative = new AppointmentTransaction();

                        if (model.SaveRelativeAsPatient == true)
                        {
                            //transaction for registration
                            commonTransactionForRelative = new AppointmentTransaction
                            {
                                AppointmentId = relativeAsPatient.PatientId, // respective Id
                                Transaction = model.Transaction ?? "",
                                TransactionDate = DateTime.Now,
                                TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                                VoucherNumber = model.SalucroStatusCode == 1201 ? null : await this.appointmentTransactionsServices.GetVoucherNumber(),
                                BankReference = "",
                                BankCode = "",
                                Active = true,
                                PaymentId = 0,
                                PaymentModeId = 1,
                                SettledAmount = (decimal)Total,
                                CreatedBy = (int)model.CreatedBy,
                                CreatedDate = DateTime.Now,
                                SalucroStatusCode = model.SalucroStatusCode,
                                SalucroTransactionId = model.SalucroTransactionId,
                                LocationId = model.LocationId,
                                ReceiptTypeId = (int)ReceiptType.Cash, // credit
                                ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,
                                PatientId = relativeAsPatient.PatientId,
                                PayStatus = 'F'
                            };
                            commonTransactionForRelative.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransactionForRelative, transaction);
                            if (commonTransactionForRelative.AppointmentTransactionId == 0)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }

                        if (model.SalucroStatusCode != 1201)
                        {
                            if (model.PaymentInitiationLogId != null && model.PaymentInitiationLogId != 0)
                            {
                                PaymentMapHelperModel paymentHelper = new PaymentMapHelperModel { PaymentInitiationLogId = ((int)model.PaymentInitiationLogId), BillId = patient.PatientId };

                                paymentHelper.PaymentMapHelperId = await this.paymentMapHelperService.AddAsync(paymentHelper);
                                if (paymentHelper.PaymentMapHelperId == 0)
                                {
                                    transaction.Rollback();
                                    return new Tuple<int, int, Guid?>(0, checkIf, null);
                                }
                            }

                            var receipt = new Receipt
                            {

                                Active = true,
                                Cost = (double)Total,
                                CreatedBy = (int)model.CreatedBy,
                                CreatedDate = DateTime.Now,
                                IsAdvance = false,
                                IsRefunded = false,
                                PayTypeId = (int)model.PayTypeId,
                                PaymentDetails = model.PaymentNumber,
                                ReceiptTypeId = ReceiptType.Cash,
                                ReceiptAreaTypeId = ReceiptAreaType.PatientRegistration,
                                RespectiveId = patient.PatientId,
                                TransactionId = commonTransaction.AppointmentTransactionId,
                                MasterBillId = getbillrecord != null ? getbillrecord.MasterBillId : billId
                            };

                            receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt);
                            if (receipt.ReceiptId == 0)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                            //begin-to update bill status as genereated.
                            var allreceiptforbill = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId);
                            allreceiptforbill.ToList();
                            var receiptcostsum = 0.0;
                            foreach (var item in allreceiptforbill.ToList())
                            {
                                receiptcostsum += item.Cost;
                            }
                            var getbill = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt.MasterBillId);
                            if (receiptcostsum == getbill.NetTotal)
                            {
                                getbill.BillStatusTypeId = (int)BillStatusType.Generated;
                                getbill.ModifiedBy = (int)model.CreatedBy;
                                getbill.ModifiedDate = DateTime.Now;
                                await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                            }

                            if (model.SaveRelativeAsPatient == true)
                            {

                                var receipt2 = new Receipt
                                {

                                    Active = true,
                                    Cost = (double)Total,
                                    CreatedBy = (int)model.CreatedBy,
                                    CreatedDate = DateTime.Now,
                                    IsAdvance = false,
                                    IsRefunded = false,
                                    PayTypeId = (int)model.PayTypeId,
                                    PaymentDetails = model.PaymentNumber,
                                    ReceiptTypeId = ReceiptType.Cash,
                                    ReceiptAreaTypeId = ReceiptAreaType.PatientRegistration,
                                    RespectiveId = relativeAsPatient.PatientId,
                                    TransactionId = commonTransactionForRelative.AppointmentTransactionId,
                                    MasterBillId = secondBillId
                                };

                                receipt2.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt2);
                                if (receipt.ReceiptId == 0)
                                {
                                    transaction.Rollback();
                                    return new Tuple<int, int, Guid?>(0, checkIf, null);
                                }
                                //begin-to update bill status as genereated.
                                var allreceiptforbillRelative = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt2.MasterBillId);

                                var receiptRelativeCostsum = 0.0;
                                foreach (var item in allreceiptforbillRelative.ToList())
                                {
                                    receiptRelativeCostsum += item.Cost;
                                }
                                var getbill2 = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt2.MasterBillId);
                                if (receiptRelativeCostsum == getbill2.NetTotal)
                                {
                                    getbill2.BillStatusTypeId = (int)BillStatusType.Generated;
                                    getbill2.ModifiedBy = (int)model.CreatedBy;
                                    getbill2.ModifiedDate = DateTime.Now;
                                    await this.unitOfWork.MasterBill.UpdateAsync(getbill2);
                                }
                            }
                            //end-to update bill status as genereated.
                        }
                    }

                    transaction.Commit();

                    return new Tuple<int, int, Guid?>(account.AccountId, patient.PatientId, account.Guid);

                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <inheritdoc />
        public async Task<Tuple<int, Guid?>> AddPatientAsync(PatientModel model, PatientFamilyModel pfModel)//// look in to it for pat registration n receipt
        {
            var billId = 0;
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = await this.CheckPatientAsync(model.Mobile, model.CountryId, model.Email, model.PatientId);
                if (checkIf != 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(checkIf, null);
                }

                // Patient
                var patient = new Patient
                {
                    Active = true,
                    Salutation = model.Salutation,
                    FirstName = model.FirstName,
                    MiddleName = model.MiddleName,
                    LastName = model.LastName,
                    FullName = model.FullName,
                    FatherOrHusband = model.FatherOrHusband,
                    UMRNo = await this.GetLatestUMRNo(),
                    DateOfBirth = model.DateOfBirth,
                    Age = model.Age,
                    Gender = model.Gender,
                    MaritalStatus = model.MaritalStatus,
                    Email = model.Email,
                    Mobile = model.Mobile,
                    StreetAddress = model.StreetAddress,
                    AddressLine2 = model.AddressLine2,
                    City = model.City,
                    State = model.State,
                    Zipcode = model.Zipcode,
                    CountryId = model.CountryId,
                    ProfileImageUrl = model.ProfileImageUrl,
                    ThumbnailUrl = model.ThumbnailUrl,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow,
                    AadharNo = model.AadharNo,
                    Guid = Guid.NewGuid(),
                    // ReferredBy = model.ReferredBy,
                    PatientReferredById = model.PatientReferredById,
                    ReferredByName = model.ReferredByName,
                    LocationId = model.LocationId,
                    HWCPatientId = model.HWCPatientId,
                    Education = model.Education,
                    Occupation = model.Occupation,
                    Nationality = model.Nationality,
                    Religion = model.Religion,
                    IdProofId = model.IdProofId,
                    IdProofValue = model.IdProofValue,
                    BloodGroup = model.BloodGroup,
                    PaymentStatus = model.PaymentStatus,
                    Amount = model.Amount,
                    PayTypeId = model.PayTypeId// paymentstatus n amount payId
                };

                patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);
                if (patient.PatientId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(checkIf, null);
                }

                if ((pfModel.FullName != null) && (pfModel.Relation != null))
                {
                    var patientFamily = new PatientFamily
                    {
                        PatientId = patient.PatientId,
                        FullName = pfModel.FullName,
                        //Relation = pfModel.Relation,
                        Relation = pfModel.Relation,
                        //                        Age = pfModel.Age,

                        Age = (int)pfModel.Age,
                        Gender = pfModel.RelativeGender,
                        Active = true,
                        CreatedBy = pfModel.CreatedBy,
                        CreatedDate = pfModel.CreatedDate,
                        ContactNo = pfModel.ContactNo,
                        Education = pfModel.Education,
                        Occupation = pfModel.Occupation,
                        // DOB = pfModel.DOB
                    };

                    patientFamily.PatientFamilyId = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                    if (patientFamily.PatientFamilyId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(checkIf, null);
                    }
                }
                // Patient's Account
                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == model.Email && m.Mobile == model.Mobile && m.CountryId == model.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId > 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                // Account
                var account = new Account
                {
                    RoleId = (int)Roles.Patient,
                    ReferenceId = patient.PatientId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.UtcNow,
                    FullName = patient.FullName,
                    CountryId = patient.CountryId,
                    Email = patient.Email,
                    Mobile = patient.Mobile,
                    Active = true,
                    Guid = patient.Guid,
                    IsAgreed = false
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, null);
                }

                var location = new LocationAccountMap
                {
                    AccountId = account.AccountId,
                    LocationId = model.LocationId
                };
                var locationId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                if (locationId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, null);
                }

                //var getRegistrationCharge = await this.unitOfWork.PatientRegistrationCharges.FindAsync(x => x.Active && x.LocationId == patient.LocationId);
                //begin-MasterBill
                var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.PatientId == model.PatientId && x.BillStatusTypeId == 2 && x.ReceiptAreaTypeId == (int)ReceiptAreaType.PatientRegistration && x.ModuleId == patient.PatientId); //need to check more

                if (getbillrecord == null)
                {
                    var onebill = new MasterBill
                    {
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,//main module
                                                                                     //ModuleId = (int)ReceiptAreaType.Labs, //sub module
                        ModuleId = patient.PatientId, // module-main table id.
                        BillDate = DateTime.Now,
                        BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                        BillStatusTypeId = (int)BillStatusType.Not_Generated,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Active = true,
                        PatientId = model.PatientId,
                        Total = (double)model.Total,
                        Discount = (double)model.Discount,
                        NetTotal = (double)model.Total,
                        Rounding = (int)model.Total - (double)model.Total,
                        LocationId = model.LocationId
                    };
                    onebill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(onebill, transaction);
                    billId = onebill.MasterBillId;
                    if (onebill.MasterBillId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(0, null);
                    }
                }
                //end-MasterBill
                if (model.PaymentStatus == true)
                {
                    //transaction for registration
                    var commonTransaction = new AppointmentTransaction
                    {
                        AppointmentId = patient.PatientId, // respective Id                     
                        Transaction = "",
                        TransactionDate = DateTime.Now,
                        TransactionId = await this.appointmentTransactionsServices.GetATransactionId(),
                        VoucherNumber = await this.appointmentTransactionsServices.GetVoucherNumber(),
                        BankReference = "",
                        BankCode = "",
                        Active = true,
                        PaymentId = 0,
                        PaymentModeId = 1,
                        SettledAmount = (decimal)model.Total,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        LocationId = model.LocationId,
                        ReceiptTypeId = (int)ReceiptType.Cash, // credit
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,
                        PatientId = patient.PatientId,
                        PayStatus = 'F'
                    };
                    commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                    if (commonTransaction.AppointmentTransactionId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(0, null);
                    }

                    var receipt = new Receipt
                    {
                        Active = true,
                        Cost = model.Total,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        IsAdvance = false,
                        IsRefunded = false,
                        PayTypeId = (int)model.PayTypeId,
                        ReceiptTypeId = ReceiptType.Cash,
                        ReceiptAreaTypeId = ReceiptAreaType.PatientRegistration,
                        RespectiveId = patient.PatientId,
                        TransactionId = commonTransaction.AppointmentTransactionId,
                        MasterBillId = getbillrecord != null ? getbillrecord.MasterBillId : billId
                    };

                    receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt);
                    if (receipt.ReceiptId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(0, null);
                    }
                    //begin-to update bill status as genereated.
                    var allreceiptforbill = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId);
                    allreceiptforbill.ToList();
                    var receiptcostsum = 0.0;
                    foreach (var item in allreceiptforbill.ToList())
                    {
                        receiptcostsum += item.Cost;
                    }
                    var getbill = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt.MasterBillId);
                    if (receiptcostsum == getbill.NetTotal)
                    {
                        getbill.BillStatusTypeId = (int)BillStatusType.Generated;
                        getbill.ModifiedBy = (int)model.CreatedBy;
                        getbill.ModifiedDate = DateTime.Now;
                        await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                    }
                    //end-to update bill status as genereated.
                }

                transaction.Commit();
                return new Tuple<int, Guid?>(patient.PatientId, account.Guid);
            }
        }
        /// <inheritdoc />
        public async Task<Tuple<int, Guid?>> AddUnidentifiedPatientAsync(PatientModel model) // master/patient  /unidentify/ adding
        {
            var billId = 0;
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = 0;
                var getLatestUmrNumber = await this.GetLatestUMRNo();
                if (string.IsNullOrEmpty(getLatestUmrNumber))
                {
                    return new Tuple<int, Guid?>(checkIf, null);
                }
                var createDummyMobileNumber = string.Concat(getLatestUmrNumber.Where(char.IsNumber));
                if (string.IsNullOrEmpty(createDummyMobileNumber))
                {
                    return new Tuple<int, Guid?>(checkIf, null);
                }
                model.Mobile = (int.Parse(createDummyMobileNumber) + 1000000000).ToString();


                var getCountry = await this.unitOfWork.Countries.FindAsync(x => x.CountryName == "India");

                if (getCountry == null)
                {
                    return new Tuple<int, Guid?>(checkIf, null);
                }

                if (model.CountryId != null && model.CountryId != 0)
                {
                    getCountry.CountryId = (int)model.CountryId;
                }

                // Patient
                var patient = new Patient
                {
                    Active = true,
                    Salutation = string.Empty,
                    FirstName = getLatestUmrNumber,
                    MiddleName = model.MiddleName,
                    LastName = getLatestUmrNumber,
                    FullName = getLatestUmrNumber,
                    FatherOrHusband = String.Empty,
                    UMRNo = getLatestUmrNumber,
                    DateOfBirth = model.DateOfBirth,
                    Age = 0,
                    Gender = model.Gender,
                    MaritalStatus = model.MaritalStatus,
                    Email = model.Email,
                    Mobile = model.Mobile,
                    StreetAddress = model.StreetAddress,
                    AddressLine2 = model.AddressLine2,
                    City = model.City,
                    State = model.State,
                    Zipcode = model.Zipcode,
                    CountryId = getCountry.CountryId,
                    ProfileImageUrl = model.ProfileImageUrl,
                    ThumbnailUrl = model.ThumbnailUrl,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow,
                    AadharNo = model.AadharNo,
                    Guid = Guid.NewGuid(),
                    ReferredBy = model.ReferredBy,
                    ReferredByName = model.ReferredByName,
                    LocationId = model.LocationId,
                    HWCPatientId = model.HWCPatientId,
                    Education = model.Education,
                    Occupation = model.Occupation,
                    Nationality = model.Nationality,
                    Religion = model.Religion,
                    IdProofId = model.IdProofId,
                    IdProofValue = model.IdProofValue,
                    BloodGroup = model.BloodGroup,
                    PaymentStatus = model.PaymentStatus,//as we now have to insert payNow /Paylater for unidendify Pat. registration amt
                    PayTypeId = model.PayTypeId,//
                    PaymentNumber = model.PaymentNumber,
                    HowDidYouKnowId = model.HowDidYouKnowId,
                    EducationId = model.EducationId,
                    OccupationId = model.OccupationId,
                    BirthMark1 = model.BirthMark1,
                    BirthMark2 = model.BirthMark2,
                    IsNewPatient = true,
                    Amount = model.Amount,
                    Total = (decimal)model.Total,
                    DiscountInPercentage = model.DiscountInPercentage,
                    DiscountInRupees = model.DiscountInRupees// ??
                };
                patient.FullName = CoreFilter.FullName(patient.FirstName, patient.MiddleName, patient.LastName);
                patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);
                if (patient.PatientId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(checkIf, null);
                }

                // Patient's Account
                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == model.Email && m.Mobile == model.Mobile && m.CountryId == model.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId > 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                // Account
                var account = new Account
                {
                    RoleId = (int)Roles.Patient,
                    ReferenceId = patient.PatientId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.UtcNow,
                    FullName = patient.FullName,
                    CountryId = patient.CountryId,
                    Email = patient.Email,
                    Mobile = patient.Mobile,
                    Active = true,
                    Guid = patient.Guid,
                    IsAgreed = false
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, null);
                }

                var location = new LocationAccountMap
                {
                    AccountId = account.AccountId,
                    LocationId = model.LocationId
                };

                var locationId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                if (locationId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, null);
                }

                //var getRegistrationCharge = await this.unitOfWork.PatientRegistrationCharges.FindAsync(x => x.Active && x.LocationId == patient.LocationId);
                //begin-MasterBill
                var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.PatientId == patient.PatientId && x.BillStatusTypeId == 2 && x.ReceiptAreaTypeId == (int)ReceiptAreaType.PatientRegistration && x.ModuleId == patient.PatientId); //need to check more

                if (getbillrecord == null)
                {
                    var onebill = new MasterBill
                    {
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,//main module
                                                                                     //ModuleId = (int)ReceiptAreaType.Labs, //sub module
                        ModuleId = patient.PatientId, // module-main table id.
                        BillDate = DateTime.Now,
                        BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                        BillStatusTypeId = (int)BillStatusType.Not_Generated,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Active = true,
                        PatientId = patient.PatientId,
                        Total = (double)model.Amount,
                        Discount = (double)model.DiscountInRupees,
                        NetTotal = (double)model.Total,
                        Rounding = (int)model.Total - (double)model.Total,
                        LocationId = model.LocationId
                    };
                    try
                    {
                        onebill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(onebill, transaction);
                    }
                    catch (Exception e)
                    {
                        //ignore
                    }
                    billId = onebill.MasterBillId;
                    if (onebill.MasterBillId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(0, null);
                    }
                }
                //end-MasterBill
                if (model.PaymentStatus == true)
                {
                    //transaction for registration//
                    var commonTransaction = new AppointmentTransaction
                    {
                        AppointmentId = patient.PatientId, // respective Id                     
                        Transaction = model.Transaction ?? "",
                        TransactionDate = DateTime.Now,
                        TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                        VoucherNumber = model.SalucroStatusCode == 1201 ? null : await this.appointmentTransactionsServices.GetVoucherNumber(),
                        BankReference = "",
                        BankCode = "",
                        Active = true,
                        PaymentId = 0,
                        PaymentModeId = 1,
                        SettledAmount = (decimal)model.Total,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        LocationId = model.LocationId,
                        ReceiptTypeId = (int)ReceiptType.Cash, // credit
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,
                        SalucroStatusCode = model.SalucroStatusCode,
                        SalucroTransactionId = model.SalucroTransactionId,
                        PatientId = patient.PatientId,
                        PayStatus = 'F'
                    };
                    commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                    if (commonTransaction.AppointmentTransactionId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, Guid?>(0, null);
                    }
                    if (model.SalucroStatusCode != 1201)
                    {
                        if (model.PaymentInitiationLogId != null && model.PaymentInitiationLogId != 0)
                        {
                            PaymentMapHelperModel paymentHelper = new PaymentMapHelperModel { PaymentInitiationLogId = ((int)model.PaymentInitiationLogId), BillId = patient.PatientId };

                            paymentHelper.PaymentMapHelperId = await this.paymentMapHelperService.AddAsync(paymentHelper);
                            if (paymentHelper.PaymentMapHelperId == 0)
                            {
                                transaction.Rollback();
                                return new Tuple<int, Guid?>(0, null);
                            }
                        }

                        var receipt = new Receipt
                        {
                            Active = true,
                            Cost = model.Total,
                            CreatedBy = (int)model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            IsAdvance = false,
                            IsRefunded = false,
                            PayTypeId = (int)model.PayTypeId,
                            PaymentDetails = model.PaymentNumber,
                            ReceiptTypeId = ReceiptType.Cash,
                            ReceiptAreaTypeId = ReceiptAreaType.PatientRegistration,
                            RespectiveId = patient.PatientId,
                            TransactionId = commonTransaction.AppointmentTransactionId,
                            MasterBillId = getbillrecord != null ? getbillrecord.MasterBillId : billId
                        };

                        receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt);
                        if (receipt.ReceiptId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, Guid?>(0, null);
                        }
                        //begin-to update bill status as genereated.
                        var allreceiptforbill = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId);
                        allreceiptforbill.ToList();
                        var receiptcostsum = 0.0;
                        foreach (var item in allreceiptforbill.ToList())
                        {
                            receiptcostsum += item.Cost;
                        }
                        var getbill = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt.MasterBillId);
                        if (receiptcostsum == getbill.NetTotal)
                        {
                            getbill.BillStatusTypeId = (int)BillStatusType.Generated;
                            getbill.ModifiedBy = (int)model.CreatedBy;
                            getbill.ModifiedDate = DateTime.Now;
                            await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                        }
                        //end-to update bill status as genereated.
                    }
                }
                transaction.Commit();
                return new Tuple<int, Guid?>(patient.PatientId, account.Guid);
            }
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(PatientModel model, List<PatientEmergencyModel> patientEmergencies, List<PatientInsuranceModel> patientInsurances, PatientFamilyModel pfModel, List<PatientFamilyModel> patientFamilyModel)
        {
            var billId = 0;
            //updation hitting from master/patient/edit
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = await this.CheckPatientAsync(model.Mobile, model.CountryId, model.Email, model.PatientId);
                if (checkIf != 0)
                {
                    //transaction.Rollback();
                    //return checkIf;
                }


                // Patient
                var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == model.PatientId, transaction);
                patient.Salutation = model.Salutation;
                patient.FirstName = model.FirstName;
                patient.MiddleName = model.MiddleName;
                patient.LastName = model.LastName;
                patient.FullName = model.FullName;
                patient.FatherOrHusband = model.FatherOrHusband;
                patient.DateOfBirth = model.DateOfBirth;
                patient.Age = model.Age;
                patient.Gender = model.Gender;
                patient.MaritalStatus = model.MaritalStatus;
                patient.Email = model.Email;
                patient.Mobile = model.Mobile;
                patient.StreetAddress = model.StreetAddress;
                patient.AddressLine2 = model.AddressLine2;
                patient.City = model.City;
                patient.State = model.State;
                patient.Zipcode = model.Zipcode;
                patient.CountryId = model.CountryId;
                // patient.ProfileImageUrl = model.ProfileImageUrl;
                // patient.ThumbnailUrl = model.ThumbnailUrl;
                patient.ModifiedBy = model.ModifiedBy;
                patient.ModifiedDate = DateTime.UtcNow;
                patient.AadharNo = model.AadharNo;
                //patient.ReferredBy = model.ReferredBy;
                patient.PatientReferredById = model.PatientReferredById;
                patient.ReferredByName = model.ReferredByName;
                patient.HWCPatientId = model.HWCPatientId;
                patient.Education = model.Education;
                patient.Occupation = model.Occupation;
                patient.Nationality = model.Nationality;
                patient.Religion = model.Religion;
                patient.IdProofId = model.IdProofId;
                patient.IdProofValue = model.IdProofValue;
                patient.BloodGroup = model.BloodGroup;
                patient.PaymentStatus = model.PaymentStatus == true ? model.PaymentStatus : patient.PaymentStatus;
                patient.PayTypeId = model.PayTypeId > 0 ? model.PayTypeId : patient.PayTypeId;
                patient.PaymentNumber = model.PaymentNumber != null ? model.PaymentNumber : patient.PaymentNumber;
                patient.UMRNo = model.PaymentStatus == true && patient.TempPatient == true ? await this.GetLatestUMRNo() : patient.UMRNo;
                patient.TempPatient = model.PaymentStatus == true ? false : patient.TempPatient;
                //patient.IsNewPatient = model.PaymentStatus == true ? false : patient.IsNewPatient;
                patient.HowDidYouKnowId = model.HowDidYouKnowId;
                patient.EducationId = model.EducationId;
                patient.OccupationId = model.OccupationId;
                patient.BirthMark1 = model.BirthMark1;
                patient.BirthMark2 = model.BirthMark2;
                patient.RelationType = model.RelationType;
                patient.OccupationDetail = model.OccupationDetail;
                patient.InsuranceCompanyId = model.InsuranceId;
                patient.ReferredByNameId = model.ReferredByNameId;
                patient.Amount = model.PaymentStatus == true ? model.Amount : patient.Amount;
                patient.Total = model.PaymentStatus == true ? model.PatientTotal : patient.Total;
                patient.DiscountInPercentage = model.PaymentStatus == true ? model.DiscountInPercentage : patient.DiscountInPercentage;
                patient.DiscountInRupees = model.PaymentStatus == true ? model.DiscountInRupees : patient.DiscountInPercentage;

                // patient.Amount// no need to update amount ..bexz its one time  inserting bec registation amount might change further

                //if ((pfModel.Relation != null) && (pfModel.FullName != null))
                //{

                //    if (pfModel.PatientFamilyId != 0)
                //    {
                //        var patientFamily = await this.unitOfWork.PatientFamily.FindAsync(n => n.PatientFamilyId == pfModel.PatientFamilyId, transaction);
                //        patientFamily.PatientId = patient.PatientId;
                //        patientFamily.FullName = pfModel.FullName;
                //        //Relation = pfModel.Relation,
                //        patientFamily.Relation = pfModel.Relation;
                //        patientFamily.Age = pfModel.Age;
                //        patientFamily.Gender = pfModel.Gender;
                //        patientFamily.Active = true;
                //        patientFamily.ModifiedBy = pfModel.ModifiedBy;
                //        patientFamily.ModifiedDate = DateTime.Now;
                //        patientFamily.ContactNo = pfModel.ContactNo;
                //        patientFamily.Education = pfModel.Education;
                //        patientFamily.Occupation = pfModel.Occupation;
                //        // patientFamily.DOB = pfModel.DOB;
                //        var updatedFamily = await this.unitOfWork.PatientFamily.UpdateAsync(patientFamily, transaction);
                //        if (updatedFamily == 0)
                //        {
                //            transaction.Rollback();
                //            return 0;
                //        }
                //    }
                //    else
                //    {
                //        var patientFamily = new PatientFamily
                //        {
                //            PatientId = patient.PatientId,
                //            FullName = pfModel.FullName,
                //            //Relation = pfModel.Relation,
                //            Relation = pfModel.Relation,
                //            Age = pfModel.Age,
                //            Gender = pfModel.Gender,
                //            Active = true,
                //            CreatedBy = pfModel.CreatedBy,
                //            CreatedDate = pfModel.CreatedDate,
                //            ContactNo = pfModel.ContactNo,
                //            Education = pfModel.Education,
                //            Occupation = pfModel.Occupation,
                //            //  DOB = pfModel.DOB
                //        };

                //        patientFamily.PatientFamilyId = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                //        if (patientFamily.PatientFamilyId == 0)
                //        {
                //            transaction.Rollback();
                //            // return new Tuple<int, Guid?>(checkIf, null);
                //        }

                //    }


                //}
                if (!string.IsNullOrEmpty(model.ReferralCode) && patient.ReferralBy == null)
                {
                    var refPatient = await this.unitOfWork.Patients.FindAsync(m => m.ReferralCode == model.ReferralCode, transaction);
                    if (refPatient == null)
                    {
                        transaction.Rollback();
                        return -3;
                    }

                    patient.ReferralBy = refPatient.PatientId;

                    var wallet = new WalletModel
                    {
                        PatientId = Convert.ToInt32(refPatient.PatientId),
                        CreditedAmount = 15.00,
                        CreditedFor = patient.FullName + " sign up with referral code"
                    };

                    await this.walletServices.AddAsync(wallet);
                }

                if (string.IsNullOrEmpty(patient.ReferralCode))
                {
                    patient.ReferralCode = await this.GetReferralCode(patient.FirstName);
                }

                if (string.IsNullOrEmpty(patient.ReferralCode))
                {
                    patient.ReferralCode = await this.GetReferralCode(patient.FirstName);
                }
                var updated = await this.unitOfWork.Patients.UpdateAsync(patient, transaction);

                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                // Patient RelativeDetails

                var query = $@"DELETE FROM ""PatientFamily"" WHERE ""PatientId"" = '{model.PatientId}'";

                await this.unitOfWork.Current.ExecuteAsync(query, null, transaction);

                if (patientFamilyModel.Any())
                {
                    if (patientFamilyModel[0].FullName != null && patientFamilyModel[0].Relation != null)
                    {
                        updated = 0;
                        foreach (var item in patientFamilyModel)
                        {
                            if (item.FullName != null && item.Relation != null)
                            {
                                var patientFamily = new PatientFamily
                                {
                                    PatientId = patient.PatientId,
                                    FullName = item.FullName,
                                    Relation = item.Relation,
                                    Age = item.Age != null ? (int)item.Age : 0,
                                    Gender = item.RelativeGender,
                                    Active = true,
                                    CreatedBy = Convert.ToInt32(model.ModifiedBy),
                                    CreatedDate = DateTime.UtcNow,
                                    ContactNo = item.ContactNo,
                                    Education = item.Education,
                                    Occupation = item.Occupation,
                                    DOB = item.DOB,
                                    OccupationDetails = item.OccupationDetails,
                                    BloodGroup = item.RelativeBloodGroup
                                };
                                var response = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                                if (response != 0)
                                {
                                    updated++;
                                }
                            }
                        }
                        if (updated != patientFamilyModel.Count)
                        {
                            transaction.Rollback();
                            return 0;
                        }
                    }

                }

                // Patient Emergencies
                query = $@"DELETE FROM ""PatientEmergency"" WHERE ""PatientId"" = '{model.PatientId}'";
                await this.unitOfWork.Current.ExecuteAsync(query, null, transaction);

                if (patientEmergencies.Any())
                {
                    updated = 0;
                    foreach (var item in patientEmergencies)
                    {
                        //int response;
                        //if (item.PatientEmergencyId > 0)
                        //{
                        //    var patientEmergency = await this.unitOfWork.PatientEmergencies.FindAsync(m => m.PatientEmergencyId == item.PatientEmergencyId, transaction);
                        //    patientEmergency.FullName = item.FullName;
                        //    patientEmergency.Relation = item.Relation;
                        //    patientEmergency.Address = item.Address;
                        //    patientEmergency.Mobile = item.Mobile;
                        //    patientEmergency.ModifiedBy = model.ModifiedBy;
                        //    patientEmergency.ModifiedDate = DateTime.UtcNow;

                        //    response = await this.unitOfWork.PatientEmergencies.UpdateAsync(patientEmergency, transaction);
                        //}
                        //else
                        //{

                        if (item.FullName != null && item.Relation != null && item.Mobile != null)
                        {

                            var patientEmergency = new PatientEmergency
                            {
                                FullName = item.FullName,
                                Relation = item.Relation,
                                Address = item.Address,
                                PatientId = model.PatientId,
                                Mobile = item.Mobile,
                                CreatedBy = Convert.ToInt32(model.ModifiedBy),
                                CreatedDate = DateTime.UtcNow,
                                Active = true

                            };
                            var response = await this.unitOfWork.PatientEmergencies.InsertAsync(patientEmergency, transaction);
                            //}

                            if (response != 0)
                            {
                                updated++;
                            }
                        }
                    }

                    if (updated != patientEmergencies.Count)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }


                // Patient Insurances
                //query = $@"DELETE FROM ""PatientInsurance"" WHERE ""PatientId"" = '{model.PatientId}'";
                //await this.unitOfWork.Current.ExecuteAsync(query, null, transaction);

                if (patientInsurances.Any())
                {
                    updated = 0;
                    foreach (var item in patientInsurances)
                    {
                        // int response;
                        //if (item.PatientInsuranceId > 0)
                        //{
                        //    var patientInsurance = await this.unitOfWork.PatientInsurances.FindAsync(m => m.PatientInsuranceId == item.PatientInsuranceId, transaction);
                        //    patientInsurance.CardNo = item.CardNo;
                        //    patientInsurance.InsuranceCompanyId = item.InsuranceCompanyId;
                        //    patientInsurance.Validity = item.Validity;
                        //    patientInsurance.ModifiedBy = model.ModifiedBy;
                        //    patientInsurance.ModifiedDate = DateTime.UtcNow;

                        //    response = await this.unitOfWork.PatientInsurances.UpdateAsync(patientInsurance, transaction);
                        //}
                        //else
                        //{
                        var response = 0;
                        var insuranceRecord = await this.unitOfWork.PatientInsurances.FindAsync(x => x.PatientInsuranceId == item.PatientInsuranceId);
                        var insuranceApprovalRecord = await this.unitOfWork.InsuranceApproval.FindAsync(x => x.PatientInsuranceId == item.PatientInsuranceId);
                        if (insuranceRecord != null && insuranceApprovalRecord != null)
                        {

                            insuranceRecord.CardNo = item.CardNo;
                            insuranceRecord.InsuranceCompanyId = (int)item.InsuranceCompanyId;
                            insuranceRecord.InsuranceTypeId = (int)item.InsuranceTypeId;
                            insuranceRecord.Validity = (DateTime)item.Validity;
                            insuranceRecord.ModifiedBy = Convert.ToInt32(model.ModifiedBy);
                            insuranceRecord.ModifiedDate = DateTime.UtcNow;
                            insuranceRecord.Active = true;

                            response = await this.unitOfWork.PatientInsurances.UpdateAsync(insuranceRecord, transaction);

                        }
                        else if (insuranceRecord != null)
                        {
                            query = $@"DELETE FROM ""PatientInsurance"" WHERE ""PatientInsuranceId"" = '{insuranceRecord.PatientInsuranceId}'";
                            await this.unitOfWork.Current.ExecuteAsync(query, null, transaction);

                            var patientInsurance = new PatientInsurance
                            {
                                PatientId = model.PatientId,
                                CardNo = item.CardNo,
                                InsuranceCompanyId = (int)item.InsuranceCompanyId,
                                InsuranceTypeId = (int)item.InsuranceTypeId,
                                Validity = (DateTime)item.Validity,
                                CreatedBy = Convert.ToInt32(model.ModifiedBy),
                                CreatedDate = DateTime.UtcNow,
                                Active = true
                            };

                            response = await this.unitOfWork.PatientInsurances.InsertAsync(patientInsurance, transaction);
                        }
                        else
                        {
                            var patientInsurance = new PatientInsurance
                            {
                                PatientId = model.PatientId,
                                CardNo = item.CardNo,
                                InsuranceCompanyId = (int)item.InsuranceCompanyId,
                                InsuranceTypeId = (int)item.InsuranceTypeId,
                                Validity = (DateTime)item.Validity,
                                CreatedBy = Convert.ToInt32(model.ModifiedBy),
                                CreatedDate = DateTime.UtcNow,
                                Active = true
                            };

                            response = await this.unitOfWork.PatientInsurances.InsertAsync(patientInsurance, transaction);
                        }

                        if (response != 0)
                        {
                            updated++;
                        }
                    }

                    if (updated != patientInsurances.Count)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }

                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == patient.PatientId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (account.Email != patient.Email || account.Mobile != patient.Mobile || account.CountryId != patient.CountryId || account.FullName != patient.FullName)
                {
                    account.Email = patient.Email;
                    account.Mobile = patient.Mobile;
                    account.CountryId = patient.CountryId;
                    account.FullName = patient.FullName;
                    updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                    if (updated == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }
                var locationId = model.LoginLocationId != null ? model.LoginLocationId : model.LocationId;
                //var getRegistrationCharge = await this.unitOfWork.PatientRegistrationCharges.FindAsync(x => x.Active && x.LocationId == locationId);//need to check location to get proper registration,
                //var checkReceipt = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>($@"SELECT COUNT(""ReceiptId"") FROM ""Receipt"" WHERE ""RespectiveId"" = {model.PatientId} and ""ReceiptAreaTypeId""=3 ");
                //check for MasterBill to update
                //begin-MasterBill
                var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.PatientId == model.PatientId && x.ReceiptAreaTypeId == (int)ReceiptAreaType.PatientRegistration && x.ModuleId == model.PatientId); //need to check more
                                                                                                                                                                                                                         //for existing patient doesnot have masterbill entry
                if (getbillrecord == null)
                {
                    var onebill = new MasterBill
                    {
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,//main module
                                                                                     //ModuleId = (int)ReceiptAreaType.Labs, //sub module
                        ModuleId = patient.PatientId, // module-main table id.
                        BillDate = DateTime.Now,
                        BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                        BillStatusTypeId = (int)BillStatusType.Not_Generated,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Active = true,
                        PatientId = model.PatientId,
                        Total = (double)model.Amount,
                        Discount = (double)model.DiscountInRupees,
                        NetTotal = (double)model.Total,
                        Rounding = (int)model.Total - (double)model.Total,
                        LocationId = model.LocationId
                    };
                    onebill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(onebill, transaction);
                    billId = onebill.MasterBillId;
                    if (onebill.MasterBillId == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }
                else
                {
                    getbillrecord.Total = (double)model.Amount;
                    getbillrecord.Discount = (double)model.DiscountInRupees;
                    getbillrecord.NetTotal = (double)model.Total;

                    var res = await this.unitOfWork.MasterBill.UpdateAsync(getbillrecord, transaction);
                    //end-MasterBill
                    if (res == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }

                //end-MasterBill

                if (model.PaymentStatus == true)
                {
                    //transaction for registration
                    var commonTransaction = new AppointmentTransaction
                    {
                        AppointmentId = patient.PatientId, // respective Id                     
                        Transaction = "",
                        TransactionDate = DateTime.Now,
                        TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                        VoucherNumber = model.SalucroStatusCode == 1201 ? null : await this.appointmentTransactionsServices.GetVoucherNumber(),
                        BankReference = "",
                        BankCode = "",
                        Active = true,
                        PaymentId = 0,
                        PaymentModeId = 1,
                        SettledAmount = (decimal)model.Total,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,

                        LocationId = model.LocationId,
                        ReceiptTypeId = (int)ReceiptType.Cash, // credit
                        ReceiptAreaTypeId = (int)ReceiptAreaType.PatientRegistration,
                        PatientId = patient.PatientId,
                        PayStatus = 'F'
                    };
                    commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                    if (commonTransaction.AppointmentTransactionId == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }

                    if (model.SalucroStatusCode != 1201)
                    {
                        if (model.PaymentInitiationLogId != null && model.PaymentInitiationLogId != 0)
                        {
                            PaymentMapHelperModel paymentHelper = new PaymentMapHelperModel { PaymentInitiationLogId = ((int)model.PaymentInitiationLogId), BillId = model.PatientId };

                            paymentHelper.PaymentMapHelperId = await this.paymentMapHelperService.AddAsync(paymentHelper);
                            if (paymentHelper.PaymentMapHelperId == 0)
                            {
                                transaction.Rollback();
                                return 0;
                            }
                        }

                        var receipt = new Receipt
                        {
                            Active = true,
                            Cost = model.Total,
                            CreatedBy = (int)model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            IsAdvance = false,
                            IsRefunded = false,
                            PayTypeId = (int)model.PayTypeId,
                            PaymentDetails = model.PaymentNumber,
                            ReceiptTypeId = ReceiptType.Cash,
                            ReceiptAreaTypeId = ReceiptAreaType.PatientRegistration,
                            RespectiveId = patient.PatientId,
                            TransactionId = commonTransaction.AppointmentTransactionId,
                            MasterBillId = getbillrecord != null ? getbillrecord.MasterBillId : billId
                        };

                        receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt);
                        if (receipt.ReceiptId == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }
                        //begin-to update bill status as genereated.
                        var allreceiptforbill = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId);
                        allreceiptforbill.ToList();
                        var receiptcostsum = 0.0;
                        foreach (var item in allreceiptforbill.ToList())
                        {
                            receiptcostsum += item.Cost;
                        }
                        var getbill = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt.MasterBillId);
                        if (receiptcostsum == getbill.NetTotal)
                        {
                            getbill.BillStatusTypeId = (int)BillStatusType.Generated;
                            getbill.ModifiedBy = (int)model.CreatedBy;
                            getbill.ModifiedDate = DateTime.Now;
                            await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                        }
                        //end-to update bill status as genereated.
                    }
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<int> EditAsync(EditPatientModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var checkIf = await this.CheckPatientAsync(model.Mobile, model.CountryId, model.Email, model.PatientId);
                if (checkIf != 0)
                {
                    //transaction.Rollback();
                    //return checkIf;
                }



                // Patient
                var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == model.PatientId, transaction);
                patient.DateOfBirth = !string.IsNullOrEmpty(model.DateOfBirth) ? Convert.ToDateTime(model.DateOfBirth) : patient.DateOfBirth;
                patient.Age = model.Age ?? patient.Age;
                patient.FirstName = model.FirstName ?? patient.FirstName;
                patient.LastName = model.LastName ?? patient.LastName;
                patient.FullName = model.FullName ?? patient.FullName;
                patient.FatherOrHusband = model.FatherOrHusband ?? patient.FatherOrHusband;
                patient.Gender = model.Gender ?? patient.Gender;
                patient.Email = model.Email;
                patient.Mobile = model.Mobile ?? patient.Mobile;
                patient.CountryId = model.CountryId ?? patient.CountryId;
                patient.ModifiedBy = model.ModifiedBy;
                patient.ModifiedDate = DateTime.UtcNow;
                patient.HWCPatientId = model.HWCPatientId;
                patient.UMRNo = patient.TempPatient == true ? model.Mobile : patient.UMRNo;
                patient.StreetAddress = model.StreetAddress;
                patient.AddressLine2 = model.AddressLine2;
                patient.Zipcode = model.Zipcode;
                patient.City = model.City;
                patient.State = model.State;
                patient.ReferredByName = model.ReferredByName;
                patient.ReferredBy = model.ReferredBy;
                patient.Salutation = model.Salutation;





                if (!string.IsNullOrEmpty(model.ReferralCode))
                {
                    var refPatient = await this.unitOfWork.Patients.FindAsync(m => m.ReferralCode == model.ReferralCode, transaction);
                    if (refPatient == null)
                    {
                        transaction.Rollback();
                        return -3;
                    }

                    patient.ReferralBy = refPatient.PatientId;

                    var wallet = new WalletModel
                    {
                        PatientId = Convert.ToInt32(refPatient.PatientId),
                        CreditedAmount = 15.00,
                        CreditedFor = patient.FullName + " sign up with referral code"
                    };

                    await this.walletServices.AddAsync(wallet);
                }

                if (string.IsNullOrEmpty(patient.ReferralCode))
                {
                    patient.ReferralCode = await this.GetReferralCode(patient.FirstName);
                }

                var updated = await this.unitOfWork.Patients.UpdateAsync(patient, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == patient.PatientId && m.Active, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (account.Email != patient.Email || account.Mobile != patient.Mobile || account.CountryId != patient.CountryId || account.FullName != patient.FullName)
                {
                    account.Email = patient.Email;
                    account.Mobile = patient.Mobile;
                    account.CountryId = patient.CountryId;
                    account.FullName = patient.FullName;
                    updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                    if (updated == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }

                transaction.Commit();
                return updated;
            }

        }

        /// <inheritdoc />
        public Task<int> UpdateImageUrlsAsync(PatientModel model, Guid guid)
        {
            var query = $@"UPDATE ""Patient"" SET ""ProfileImageUrl"" = '{model.ProfileImageUrl}', ""ThumbnailUrl"" = '{model.ThumbnailUrl}' WHERE ""Guid""= '{guid}'";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<int> CheckPatientAsync(string mobile, int? countryId, string email, int patientId)
        {
            int checkIf;
            if (!string.IsNullOrEmpty(mobile) && countryId != null && countryId != 0)
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE ""Mobile"" = '{mobile}' AND ""CountryId"" = '{countryId}' AND ""PatientId"" <> {patientId}");
                if (checkIf > 0)
                {
                    return -1;
                }
            }

            if (!string.IsNullOrEmpty(email))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE TRIM(UPPER(""Email"")) = '{email.ToUpper().Trim()}' AND ""PatientId"" <> {patientId} AND ""Email"" != ''");
                if (checkIf > 0)
                {
                    return -2;
                }
            }

            return 0;
        }


        public async Task<int> CheckPatientUMRNo(string mobile)
        {
            int checkIf;
            if (!string.IsNullOrEmpty(mobile))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PatientId"") FROM ""Patient"" WHERE ""UMRNo""='{mobile}'");
                if (checkIf > 0)
                {
                    return -1;
                }
            }
            return 0;
        }
        /// <inheritdoc />
        public async Task<int> ModifyStatusAsync(PatientModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                // Patient
                var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == model.PatientId, transaction);
                patient.Active = model.Active;
                patient.ModifiedBy = model.ModifiedBy;
                patient.ModifiedDate = DateTime.UtcNow;

                var updated = await this.unitOfWork.Patients.UpdateAsync(patient, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == patient.PatientId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                account.Active = model.Active;
                account.ModifiedBy = model.ModifiedBy;
                account.ModifiedDate = DateTime.UtcNow;

                updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<int> LockedStatusAsync(PatientModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == model.PatientId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                account.IsLocked = Convert.ToBoolean(model.IsLocked);
                account.ModifiedBy = model.ModifiedBy;
                account.ModifiedDate = DateTime.UtcNow;

                var updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<int> AddFamilyMember(PatientFamilyModel model)
        {
            var record = new PatientFamily
            {
                FullName = model.FullName,
                //                Age = model.Age,

                Age = (int)model.Age,
                Active = true,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow,
                Gender = model.RelativeGender,
                //                PatientId = model.PatientId,

                PatientId = (int)model.PatientId,
                Relation = model.Relation
            };
            return await this.unitOfWork.PatientFamily.InsertAsync(record);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PatientFamilyModel>> FetchFamilyMembers(int patientId)
        {
            //var query =
            //    $@"SELECT ""PatientFamilyId"", ""PatientId"", ""FullName"", ""Relation"", ""Age"", ""Gender"", ""Active""
            //                     FROM ""PatientFamily"" where ""PatientId"" = {patientId} and ""Active"" = true order by ""CreatedDate"" desc";
            var query = $@"SELECT pp.""PatientFamilyId"", p.""FullName""as ""PatientName"",pp.""PatientId"", pp.""FullName"", pp.""Relation"", pp.""Age"", pp.""Gender"", pp.""Active""

                                    FROM ""PatientFamily"" pp
                                    join ""Patient"" p on p.""PatientId"" = pp.""PatientId""

                                    where pp.""PatientId"" = {patientId}
            and pp.""Active"" = true order by pp.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<PatientFamilyModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> UpdateFamilyMembers(PatientFamilyModel model)
        {
            var record = new PatientFamily
            {
                PatientFamilyId = (int)model.PatientFamilyId,
                FullName = model.FullName,
                Age = (int)model.Age,
                Active = true,
                Gender = model.RelativeGender,
                PatientId = (int)model.PatientId,
                Relation = model.Relation,
                ModifiedBy = model.ModifiedBy,
                ModifiedDate = DateTime.UtcNow
            };
            return await this.unitOfWork.PatientFamily.UpdateAsync(record);
        }

        /// <inheritdoc />
        public async Task<int> DeleteFamilyMember(PatientFamilyModel model)
        {
            var query = $@"Delete from ""PatientFamily"" where ""PatientFamilyId"" = {model.PatientFamilyId} ";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<int> ManualVerifyAsync(PatientModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                // Patient
                var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == model.PatientId, transaction);

                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == patient.PatientId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                account.ManualVerified = true;
                account.ModifiedBy = model.ModifiedBy;
                account.ModifiedDate = DateTime.UtcNow;

                var updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<string> GetReferralCodeAsync(int patientId)
        {
            // Patient
            var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == patientId);
            if (string.IsNullOrEmpty(patient.ReferralCode))
            {
                patient.ReferralCode = await this.GetReferralCode(patient.FirstName);
                await this.unitOfWork.Patients.UpdateAsync(patient);
            }

            return patient.ReferralCode;
        }

        /// <inheritdoc />
        public async Task<bool> VerifyReferralCodeAsync(string referralCode)
        {
            // Patient
            return await this.unitOfWork.Patients.FindAsync(m => m.ReferralCode == referralCode) != null;
        }

        /// <inheritdoc />
        public async Task<int> GetReferralByAsync(string referralCode)
        {
            // Patient
            var patient = await this.unitOfWork.Patients.FindAsync(m => m.ReferralCode == referralCode);
            if (patient != null)
            {
                return patient.PatientId;
            }
            return patient.PatientId;
        }

        /// <summary>
        /// The get latest UMR no.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<string> GetLatestUMRNo()
        {
            // Ex: UMR20010005
            var umrNo = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<string>($@"SELECT ""UMRNo"" FROM ""Patient"" where ""UMRNo"" LIKE 'UMR%' ORDER BY ""UMRNo"" DESC limit 1");
            if (umrNo != null)
            {
                var text = Regex.Replace(umrNo, @"[\d-]", string.Empty);
                var number = umrNo.Replace(text, string.Empty);
                var sequence = Convert.ToInt64(number) + 1;
                return $@"{text}{sequence}";
            }
            else
            {
                return $@"UMR400000";
            }
        }

        /// <summary>
        /// The get referral code.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<string> GetReferralCode(string name)
        {
            if (!string.IsNullOrEmpty(name))
            {
                var refName = name.Trim().Split(" ")[0].Trim().ToUpper();
                for (int i = refName.Length; i < 5; i++)
                {
                    refName += "0";
                }

                refName = refName.Substring(0, 4);

                var referralCode = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<string>($@"SELECT ""ReferralCode"" FROM ""Patient"" WHERE (""ReferralCode"" ILIKE '%{refName}%') ORDER BY ""PatientId"" DESC");

                return CoreFilter.GetReferralCode(refName, referralCode);
            }

            return null;
        }

        public async Task<InsertModel> FindPatientByPatientId(int patientId)
        {
            var data = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == patientId);

            return new InsertModel
            {

                PatientId = data.PatientId,
                FullName = data.FullName,
            };

        }

        public async Task<string> FindPatientByAdmissionId(int admissionId)
        {
            var query = $@"SELECT ""FullName"" FROM ""Patient"" p WHERE P.""PatientId"" = (SELECT ""PatientId"" FROM ""Admission"" a WHERE a.""AdmissionId"" = {admissionId})";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        public async Task<int> GetDepartmentIdByAdmissionId(int admissionId)
        {
            var query = $@"SELECT ""DepartmentId"" FROM ""Admission"" a WHERE a.""AdmissionId"" = {admissionId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return response;
        }

        //public Task<InsertModel> FindPatientByAdmissionId(int admissionId)
        //{
        //    var query = $@"Select * from ""Admission"" where ""AdmissionId"" = {admissionId} ";
        //    return this.unitOfWork.Current.QueryFirstOrDefaultAsync<InsertModel>(query);
        //}

        //Task<InsertModel> IPatientService.FindPatientByAdmissionId(int admissionId)
        //{
        //    var query = $@"Select * from ""Admission"" where ""AdmissionId"" = {admissionId} ";
        //    return this.unitOfWork.Current.QueryFirstOrDefaultAsync<InsertModel>(query);
        //}
        public int FindPatientByAdmissionId(string email, string mobile, int patientid)
        {
            var query_ = $@"Select * from ""Admission"" where ""PatientId"" = '{patientid}' or ""Mobile"" = '{mobile}'";
            var res = this.unitOfWork.Current.ExecuteScalar<int>(query_);
            return res;
        }

        public Task<AdmissionModel> CheckForFollowUpForInPatientAsync(AdmissionModel model)
        {
            var query = $@"select pl.""FollowUpDaysForIp"", ds.""DischargeDate""  ,a.* from ""Admission"" a
                            join ""ProviderLocation"" pl on pl.""ProviderId""= a.""ProviderId""
                            join ""Discharge"" ds on ds.""AdmissionId""= a.""AdmissionId""
                            where a.""PatientId""= {model.PatientId} and a.""ProviderId"" ={model.ProviderId}
                            order by a.""AdmissionDate"" desc limit 1";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AdmissionModel>(query);
        }

        public async Task<int> UpdateDischargDateAsync(UpdateExpectedDischargeDateModel model)
        {
            var admission = await this.unitOfWork.Admission.FindAsync(x => x.AdmissionId == model.Id);
            admission.ExpectedDischargeDate = model.Date;
            admission.DischargedBy = model.DischargedBy;
            var response = await this.unitOfWork.Admission.UpdateAsync(admission);
            return response;
        }

        /// <inheritdoc />
        public Task<IEnumerable<PatientModel>> FetchPatientsAsync(PatientModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo.Trim()}'" : ",null";
            parameters += !string.IsNullOrEmpty(model.FullName) ? $@",'{model.FullName.Trim()}'" : ",null";
            parameters += $@",'{this.amazonS3Configuration.BucketURL}'";

            var query = $@"select * from ""udf_FetchPatients_For_QuickScheduleFollowUp""({parameters})";

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

        /// <inheritdoc />
        public async Task<int> ModifyPatientRegistrationCharge(PatientRegistrationChargeModel model)
        {
            var query = $@"SELECT count(""Charge"") FROM ""PatientRegistrationCharge"" where ""Charge"" = {model.Charge} group by ""Charge"";";
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query);
            if (checkIf > 0)
            {
                return -1;
            }
            var charge = new PatientRegistrationCharge
            {
                Active = false,
                Charge = model.Charge,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                LocationId = (int)model.LocationId,
                ChargeCategoryId = model.ChargeCategoryId,
                ModulesMasterId = 18,
                Name = "Patient Registration Charge"
            };
            if (model.PatientRegistrationChargeId == 0)
            {
                return await this.unitOfWork.PatientRegistrationCharges.InsertAsync(charge);
            }

            var previousDetail = await this.unitOfWork.PatientRegistrationCharges.FindAsync(m => m.PatientRegistrationChargeId == model.PatientRegistrationChargeId);
            if (previousDetail != null)
            {
                previousDetail.Charge = charge.Charge;
                previousDetail.ModifiedBy = charge.CreatedBy;
                previousDetail.ModifiedDate = charge.CreatedDate;

                return await this.unitOfWork.PatientRegistrationCharges.UpdateAsync(previousDetail);
            }
            return 0;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PatientRegistrationChargeModel>> FetchRegistrationChargesAsync(int locationId)
        {
            var query = $@"SELECT PRC.*, CA.""FullName"" as ""CreatedByName"",MA.""FullName"" as ""ModifiedByName""
	                        FROM ""PatientRegistrationCharge"" PRC
	                        join ""Account"" CA on CA.""AccountId"" = PRC.""CreatedBy""
	                        left join ""Account"" MA on MA.""AccountId"" = PRC.""ModifiedBy""
                             where PRC.""LocationId"" = {locationId} order by ""CreatedDate""";
            return await this.unitOfWork.Current.QueryAsync<PatientRegistrationChargeModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> ApplyRegistrationAsync(int id, int locationId)
        {
            var query = $@"UPDATE ""PatientRegistrationCharge""
	                        SET ""Active""= false WHERE ""LocationId""={locationId};
                        UPDATE ""PatientRegistrationCharge""
	                        SET ""Active""= true
	                        WHERE ""PatientRegistrationChargeId""= {id} and ""LocationId""={locationId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<RegistrationBillModel> FetchPatientRegistrationBillAsync(int patientId)
        {
            //var query = $@"SELECT PRD.*,A.""FullName"" as ""CreatedByName"", P.""FullName"" as ""PatientName"",
            //                 P.""Age"",P.""Gender"",PT.""PayTypeName""
            //                 FROM ""PatientRegistrationDetail"" PRD
            //                 join ""Patient"" P on P.""PatientId"" = PRD.""PatientId""
            //                 join ""Account"" A on A.""AccountId"" = PRD.""CreatedBy""
            //                 join ""PayType"" PT on PT.""PayTypeId"" = PRD.""PayTypeId"" 
            //                 where PRD.""PatientId""= {patientId} limit 1;";

            var query = $@"SELECT P.""Amount"",P.""DiscountInRupees"" ""Discount"",R.""Cost"" as ""Charge"" ,R.""RespectiveId"" as ""PatientId"" , R.""CreatedBy"" ,R.""CreatedDate"" ,
                                R.""PayTypeId"" ,R.""PaymentDetails"",
								A.""FullName"" as ""CreatedByName"", P.""FullName"" as ""PatientName"",P.""UMRNo"",
	                            P.""Age"",P.""Gender"",PT.""PayTypeName""
                                FROM ""Receipt"" R
                                join ""Patient"" P on R.""RespectiveId"" = P.""PatientId""
                                join ""Account"" A on A.""AccountId"" = R.""CreatedBy""
                                join ""PayType"" PT on PT.""PayTypeId"" = R.""PayTypeId""
                                where R.""RespectiveId"" =  {patientId} and R.""ReceiptAreaTypeId""=3";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<RegistrationBillModel>(query);

        }

        public async Task<IEnumerable<RegistrationBillModel>> FetchPatientRegistrationBillForRelativePatient(int patientId)
        {
            var patientIds = new List<int>();
            var relativeQ = $@"select ""PatientId"" from ""Patient"" p where ""Mobile"" in (select ""ContactNo""  from ""PatientFamily"" pf where pf.""PatientId"" = {patientId} and pf.""Relation"" = 'Husband')";
            var relId = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int?>(relativeQ);
            if (relId != null && relId > 0)
            {
                patientIds.Add((int)relId);
            }
            patientIds.Add(patientId);

            var returnModel = new List<RegistrationBillModel>();
            foreach (var patient in patientIds)
            {
                var query = $@"SELECT P.""Amount"",P.""DiscountInRupees"" ""Discount"",R.""Cost"" as ""Charge"" ,R.""RespectiveId"" as ""PatientId"" , R.""CreatedBy"" ,R.""CreatedDate"" ,
                                R.""PayTypeId"" ,R.""PaymentDetails"",
								A.""FullName"" as ""CreatedByName"", P.""FullName"" as ""PatientName"",
	                            P.""Age"",P.""Gender"",PT.""PayTypeName""
                                FROM ""Receipt"" R
                                join ""Patient"" P on R.""RespectiveId"" = P.""PatientId""
                                join ""Account"" A on A.""AccountId"" = R.""CreatedBy""
                                join ""PayType"" PT on PT.""PayTypeId"" = R.""PayTypeId""
                                where R.""RespectiveId"" =  {patient} and R.""ReceiptAreaTypeId""=3";
                var data = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<RegistrationBillModel>(query);
                returnModel.Add(data);
            }

            return returnModel;
        }

        /// <inheritdoc />
        public async Task<string> FetchPatientRegistrationCharges(int locationId)
        {
            var query = $@"select cmd.""Amount""::text as ""Charge""
                                from ""ChargeModuleDetails"" cmd
	                            join ""ChargeModuleCategory"" cmc ON CMC.""ChargeModuleCategoryId"" = CMD.""ChargeModuleCategoryId""
	                            join ""ModulesMaster"" mm on MM.""ModulesMasterId"" = CMC.""ModulesMasterId"" 
	                            where mm.""ModuleName"" = 'PatientRegistration'
	                            and cmc.""ChargeModuleTemplateId"" = (select ""ChargeModuleTemplateId"" from ""ChargeModuleTemplate"" where ""IsInUse"" is true and ""LocationId"" = {locationId})";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
        }

        public async Task<IEnumerable<PatientModel>> FetchPatientListAsync(PatientListModel model)
        {
            var query = $@"select p.""PatientId"",p.""FirstName"",p.""MiddleName"",p.""LastName"",p.""FullName"",p.""DateOfBirth"",p.""Age"",p.""Gender"",p.""UMRNo"",p.""Email"",p.""Mobile"",p.""LocationId"",
                            l.""Name"" as ""LocationName"",hp.""HWCName"",
                            p.""HWCPatientId"",p.""PatientReferredById"",pr.""Name"" as ""PatientReferredByName"",p.""IdProofId"",p.""BloodGroup"",
							p.""PaymentNumber"",p.""PaymentStatus"",p.""PayTypeId"",pt.""PayTypeName"",p.""TempPatient""
							,p.""HowDidYouKnowId"",hd.""Name"" as ""HowDidYouKnowName"",
                            p.""EducationId"",e.""Name"" as ""EductionName"",p.""OccupationId"",op.""Name"" as ""OccupationName"",p.""BirthMark1"",
							p.""BirthMark2"" from ""Patient"" p
							left join ""Education"" e on e.""EducationId"" = p.""EducationId""
							left join ""Occupation"" op on op.""OccupationId"" = p.""OccupationId""
							left join ""Location"" l on l.""LocationId"" =p.""LocationId""
							left join ""HWCPatient"" hp on hp.""HWCPatientId"" = p.""HWCPatientId""
							left join ""PatientReferredBy"" pr on pr.""PatientReferredById"" = p.""PatientReferredById""
							left join ""IdProof"" i on i.""IdProofId"" = p.""IdProofId""
							left join ""PayType"" pt on pt.""PayTypeId"" = p.""PayTypeId""
							left join ""HowDidYouKnow"" hd on hd.""HowDidYouKnowId"" = p.""HowDidYouKnowId"" where p.""Mobile"" = '{model.Mobile}'";
            return await this.unitOfWork.Current.QueryAsync<PatientModel>(query);
        }

        public async Task<int> UpdatePatientDetailsAsync(PatientModel model, PatientFamilyModel pfModel)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == model.PatientId, transaction);
                patient.Salutation = model.Salutation;
                patient.FirstName = model.FirstName;
                patient.MiddleName = patient.MiddleName;
                patient.LastName = model.LastName;
                patient.FullName = model.FullName;
                patient.FatherOrHusband = patient.FatherOrHusband;
                patient.DateOfBirth = model.DateOfBirth;
                patient.Age = model.Age;
                patient.Gender = model.Gender;
                patient.MaritalStatus = model.MaritalStatus;
                patient.Email = model.Email;
                patient.Mobile = model.Mobile;
                patient.StreetAddress = model.StreetAddress;
                patient.AddressLine2 = model.AddressLine2;
                patient.City = model.City;
                patient.State = model.State;
                patient.Zipcode = patient.Zipcode;
                patient.CountryId = patient.CountryId;
                patient.ModifiedBy = model.ModifiedBy;
                patient.ModifiedDate = DateTime.UtcNow;
                patient.AadharNo = patient.AadharNo;
                patient.PatientReferredById = model.PatientReferredById;
                patient.ReferredByName = model.ReferredByName;
                patient.HWCPatientId = model.HWCPatientId;
                patient.Education = patient.Education;
                patient.Occupation = patient.Occupation;
                patient.Nationality = model.Nationality;
                patient.Religion = model.Religion;
                patient.IdProofId = model.IdProofId;
                patient.IdProofValue = model.IdProofValue;
                patient.BloodGroup = patient.BloodGroup;
                patient.PaymentStatus = model.PaymentStatus;
                patient.PayTypeId = model.PayTypeId;
                patient.PaymentNumber = model.PaymentNumber;
                patient.UMRNo = patient.UMRNo;
                patient.TempPatient = model.PaymentStatus == true ? false : patient.TempPatient;
                patient.HowDidYouKnowId = patient.HowDidYouKnowId;
                patient.EducationId = model.EducationId;
                patient.OccupationId = model.OccupationId;
                //patient.BirthMark1 = model.BirthMark1;
                //patient.BirthMark2 = model.BirthMark2;
                //patient.RelationType = model.RelationType;
                patient.OccupationDetail = model.OccupationDetail;
                patient.InsuranceCompanyId = model.InsuranceId;
                var updated = await this.unitOfWork.Patients.UpdateAsync(patient, transaction);

                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                // Patient RelativeDetails
                if (pfModel.FullName != null && pfModel.Relation != null)
                {
                    var query = $@"DELETE FROM ""PatientFamily"" WHERE ""PatientId"" = '{model.PatientId}'";

                    await this.unitOfWork.Current.ExecuteAsync(query, null, transaction);
                    var patientFamily = new PatientFamily
                    {
                        PatientId = patient.PatientId,
                        FullName = pfModel.FullName,
                        Relation = pfModel.Relation,
                        Age = pfModel.Age != null ? (int)pfModel.Age : 0,
                        Gender = pfModel.RelativeGender,
                        Active = true,
                        CreatedBy = Convert.ToInt32(model.ModifiedBy),
                        CreatedDate = DateTime.UtcNow,
                        ContactNo = pfModel.ContactNo,
                        Education = pfModel.Education,
                        Occupation = pfModel.Occupation,
                        DOB = pfModel.DOB,
                        OccupationDetails = pfModel.OccupationDetails
                    };
                    var response = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                }



                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Patient && m.ReferenceId == patient.PatientId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (account.Email != patient.Email || account.Mobile != patient.Mobile || account.CountryId != patient.CountryId || account.FullName != patient.FullName)
                {
                    account.Email = patient.Email;
                    account.Mobile = patient.Mobile;
                    account.CountryId = patient.CountryId;
                    account.FullName = patient.FullName;
                    updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                    if (updated == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }
                transaction.Commit();
                return updated;
            }

        }

        /// <inheritdoc />
        public async Task<IEnumerable<PatientModel>> FetchAppointmentSchedulePatientsAsync(PatientModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo.Trim()}'" : ",null";
            parameters += !string.IsNullOrEmpty(model.FullName) ? $@",'{model.FullName.Trim()}'" : ",null";
            parameters += $@",'{this.runningEnvironment.CurrentEnvironment}'";
            parameters += model.AppointmentId != null ? $@", {model.AppointmentId}" : ",null";

            var query = $@"select * from ""udf_FetchPatients_For_AppointmentScheduleFollowUp""({parameters})";

            var appointmentSchedulePatient = await this.unitOfWork.Current.QueryAsync<PatientModel>(query);


            var appointmentModels = appointmentSchedulePatient.ToList();
            if (appointmentModels.Count > 0 && model.ProviderId != null || model.LocationId != null)
                foreach (var appointment in appointmentModels)
                {
                    var apptsQuery = $@"select A.""AppointmentId"",A.""AppointmentTime"",A.""AppointmentDate""::Date,P.""FullName"" as ""ProviderName"",A.""Total"" from ""Appointment"" A
                                    join ""Provider"" P on P.""ProviderId""=A.""ProviderId""
                                    where A.""PatientId""={appointment.PatientId} order by A.""AppointmentId"" desc";
                    var appts = await this.unitOfWork.Current.QueryAsync<AppointmentModel>(apptsQuery);
                    if (appts != null && appts.Count() > 1)
                    {
                        var appt = appts.ToList()[0];
                        var nextAppt = appt.AppointmentId != appointment.AppointmentId ? appt : null;

                        if (nextAppt != null)
                        {

                            var time = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd")).Add(nextAppt.AppointmentTime).ToString("hh:mm tt");
                            appointment.NextAppointment = $@"Given on {nextAppt.AppointmentDate:yyyy-MM-dd} To Dr.{nextAppt.ProviderName} at {time}.";
                        }
                        var lastAppt = appts.ToList()[1];
                        appointment.LastConsultedDate = lastAppt.AppointmentDate;
                        appointment.LastConsultedTime = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd")).Add(lastAppt.AppointmentTime).ToString("hh:mm tt");

                        appointment.LastConsultedDoctor = lastAppt.ProviderName;
                        appointment.LastPaidAmount = lastAppt.Total;
                    }
                }
            return appointmentSchedulePatient;
        }

        public async Task<IEnumerable<ANCCardGenerationModel>> FetchANCCard(int patientId)
        {
            var where = $@" where 1=1";
            if (patientId > 0)
            {
                where += $@" and ""PatientId""={patientId}";
            }
            var query = $@"select ""ANCNo"",""Department"",""HusbandName"",""RegistrationDate"",""PatientId"" from ""ANCCardGeneration"" {where} union
select ""GYNNo"",""Department"",""HusbandName"",""RegistrationDate"",""PatientId"" from ""GYNCardGeneration"" {where}";
            return await this.unitOfWork.Current.QueryAsync<ANCCardGenerationModel>(query);
        }

        public async Task<Tuple<int, int, Guid?>> AddBabyPatientAsync(PatientModel model, List<PatientEmergencyModel> patientEmergencies, List<PatientInsuranceModel> patientInsurances, PatientFamilyModel pfModel, List<PatientFamilyModel> patientFamilyModel)
        {

            {
                using (var transaction = this.unitOfWork.BeginTransaction())
                {
                    var checkIf = await this.CheckPatientAsync(model.Mobile, model.CountryId, model.Email, model.PatientId);
                    if (checkIf != 0)
                    {
                        //transaction.Rollback();
                        //return new Tuple<int, int, Guid?>(checkIf, checkIf, null);
                    }
                    if (model.PaymentStatus != true && model.IsBabyRegistration != true)
                    {
                        var checkUMRNo = await this.CheckPatientUMRNo(model.Mobile);
                        if (checkUMRNo != 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(checkUMRNo, checkUMRNo, null);

                        }
                    }

                    var umrNo = "";
                    if (model.IsBabyRegistration != true)
                    {
                        if (!string.IsNullOrEmpty(model.REGNO))
                        {
                            umrNo = model.REGNO;
                        }
                        else
                        {
                            umrNo = model.PaymentStatus == true ? await this.GetLatestUMRNo() : model.Mobile;
                        }
                    }
                    if (model.IsBabyRegistration == true)
                    {
                        umrNo = await this.GetLatestUMRNo();
                    }
                    try
                    {
                        var patient = new Patient
                        {
                            Active = true,
                            Salutation = model.Salutation,
                            FirstName = model.FirstName,
                            MiddleName = model.MiddleName,
                            LastName = model.LastName,
                            AadharNo = model.AadharNo,
                            FullName = model.FullName,
                            FatherOrHusband = model.FatherOrHusband,
                            UMRNo = umrNo,
                            TempPatient = model.PaymentStatus == false ? true : false,
                            DateOfBirth = model.DateOfBirth,
                            Age = model.Age,
                            Gender = model.Gender,
                            MaritalStatus = model.MaritalStatus,
                            Email = model.Email,
                            Mobile = model.Mobile,
                            StreetAddress = model.StreetAddress,
                            AddressLine2 = model.AddressLine2,
                            City = model.City,
                            State = model.State,
                            Zipcode = model.Zipcode,
                            CountryId = model.CountryId,
                            CreatedBy = model.CreatedBy,
                            CreatedDate = DateTime.UtcNow,
                            Guid = Guid.NewGuid(),
                            PatientReferredById = model.PatientReferredById,
                            ReferredByName = model.ReferredByName,
                            LocationId = model.LocationId,
                            HWCPatientId = model.HWCPatientId,
                            Education = model.Education,
                            Occupation = model.Occupation,
                            Nationality = model.Nationality,
                            Religion = model.Religion,
                            IdProofId = model.IdProofId,
                            IdProofValue = model.IdProofValue,
                            BloodGroup = model.BloodGroup,
                            PaymentNumber = model.PaymentNumber,
                            PaymentStatus = model.PaymentStatus,
                            PayTypeId = model.PaymentStatus == true ? model.PayTypeId : null,
                            HowDidYouKnowId = model.HowDidYouKnowId,
                            EducationId = model.EducationId,
                            OccupationId = model.OccupationId,
                            BirthMark1 = model.BirthMark1,
                            BirthMark2 = model.BirthMark2,
                            OccupationDetail = model.OccupationDetail,
                            IsNewPatient = true,
                            InsuranceCompanyId = model.InsuranceId,
                            ReferredByNameId = model.ReferredByNameId,
                            IsBabyRegistration = model.IsBabyRegistration,
                            ParentPatientId = model.IsBabyRegistration == true ? model.ParentPatientId : null,
                            TimeOfBirth = model.TimeOfBirth
                        };
                        patient.PatientId = await this.unitOfWork.Patients.InsertAsync(patient, transaction);



                        // Patient

                        if (patient.PatientId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(checkIf, checkIf, null);
                        }
                        //Patient Relative Details
                        if (patientFamilyModel.Any())
                        {
                            var completed = 0;
                            foreach (var patientFamily in patientFamilyModel.Select(item => new PatientFamily
                            {

                                PatientId = patient.PatientId,
                                FullName = item.FullName,
                                Relation = item.Relation,
                                Age = item.Age != null ? (int)item.Age : 0,
                                Gender = item.RelativeGender,
                                Active = true,
                                CreatedBy = Convert.ToInt32(model.CreatedBy),
                                CreatedDate = DateTime.UtcNow,
                                ContactNo = item.ContactNo,
                                Education = item.Education,
                                Occupation = item.Occupation,
                                DOB = item.DOB,
                                OccupationDetails = item.OccupationDetails,
                                BloodGroup = item.RelativeBloodGroup,
                            }
                        ))
                            {
                                patientFamily.PatientFamilyId = await this.unitOfWork.PatientFamily.InsertAsync(patientFamily, transaction);
                            }
                            if (completed != patientFamilyModel.Count)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }

                        // Patient Emergency Contacts
                        if (patientEmergencies.Any())
                        {
                            var inserted = 0;
                            foreach (var patientEmergency in patientEmergencies.Select(item => new PatientEmergency
                            {
                                Active = true,
                                CreatedDate = DateTime.UtcNow,
                                CreatedBy = Convert.ToInt32(model.CreatedBy),
                                PatientId = patient.PatientId,
                                Address = item.Address,
                                FullName = item.FullName,
                                Mobile = item.Mobile,
                                Relation = item.Relation
                            }))
                            {
                                patientEmergency.PatientEmergencyId = await this.unitOfWork.PatientEmergencies.InsertAsync(patientEmergency, transaction);
                                if (patientEmergency.PatientEmergencyId != 0)
                                {
                                    inserted++;
                                }
                            }

                            if (inserted != patientEmergencies.Count)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }

                        // Patient Insurances
                        if (patientInsurances.Any())
                        {
                            var inserted = 0;
                            foreach (var patientInsurance in patientInsurances.Select(item => new PatientInsurance
                            {
                                Active = true,
                                CreatedDate = DateTime.UtcNow,
                                CreatedBy = Convert.ToInt32(model.CreatedBy),
                                PatientId = patient.PatientId,
                                InsuranceCompanyId = (int)item.InsuranceCompanyId,
                                CardNo = item.CardNo,
                                //                        Validity = item.Validity,

                                Validity = (DateTime)item.Validity,
                                InsuranceTypeId = (int)item.InsuranceTypeId
                            }))
                            {
                                patientInsurance.PatientInsuranceId = await this.unitOfWork.PatientInsurances.InsertAsync(patientInsurance, transaction);
                                if (patientInsurance.PatientInsuranceId != 0)
                                {
                                    inserted++;
                                }
                            }

                            if (inserted != patientInsurances.Count)
                            {
                                transaction.Rollback();
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }

                        // Patient's Account
                        var saltKey = CoreFilter.Random(10);
                        var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == model.Email && m.Mobile == model.Mobile && m.CountryId == model.CountryId, transaction);
                        if (existingAccount != null && existingAccount.AccountId > 0)
                        {
                            saltKey = existingAccount.SaltKey;
                        }

                        // Account
                        var account = new Account
                        {
                            RoleId = (int)Roles.Patient,
                            ReferenceId = patient.PatientId,
                            SaltKey = saltKey,
                            CreatedDate = DateTime.UtcNow,
                            FullName = patient.FullName,
                            CountryId = patient.CountryId,
                            Email = patient.Email,
                            Mobile = patient.Mobile,
                            Active = true,
                            Guid = patient.Guid,
                            IsAgreed = false
                        };

                        account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                        if (account.AccountId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }
                        // Location
                        var location = new LocationAccountMap
                        {
                            AccountId = account.AccountId,
                            LocationId = model.LocationId
                        };
                        var locationId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                        if (locationId == 0)
                        {
                            transaction.Rollback();
                            return new Tuple<int, int, Guid?>(0, checkIf, null);
                        }

                        transaction.Commit();

                        return new Tuple<int, int, Guid?>(account.AccountId, patient.PatientId, account.Guid);

                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                }
            }
        }

        public async Task<PatientTimeLineModel> FetchPatientTimeLine(int? patientId)
        {
            var fromDate = Convert.ToDateTime(DateTime.Now);
            var labModel = new LabBookingModel();
            labModel.PatientId = patientId;
            labModel.FromDate = fromDate.ToString();
            var appointmentModel = new AppointmentFilterModel();
            appointmentModel.PatientId = patientId;

            var where = $@" where 1=1";

            var paramsString = $@"";
            //var paramsString1 = $@"";
            var response = new PatientTimeLineModel();
            if (patientId != 0)
            {
                paramsString += $@"null,null, {patientId},null, null, null, null, null, null, null, null,0,10";
            }
            //if (patientId > 0)
            //{
            //    paramsString1 += $@"null,null,{patientId},null,null,null,null,null,null, null, null, null,null, null";
            //}
            if (patientId > 0)
            {
                where += $@" and bs.""PatientId"" = {patientId}";
            }
            var appointmentWhere = $@"where 1=1 and ad.""PatientId""={patientId}";
            var appointmentQuery = $@"select pa.""PatientId"",ad.""PaymentStatus"",et.""EncounterName"",sp.""SpecializationName"", ad.""Status"",vt.""VisitorName"",A.""FullName"",Rl.""RoleName"",
                                        Ad.""FollowUpForAppointmentId"",
	                                    Ad.""AppointmentDate"",Ad.""AppointmentNo"", Ad.""AppointmentTime"",Ad.""LocationId"",Ad.""IsHealthCard"",
                                        pa.""FullName"" ""PatientName"",Pa.""UMRNo"",pa.""Mobile"",pr.""FullName"" as ""ProviderName"",Ad.""PaymentType"",
                                        ad.""PaymentNumber"" as ""PaymentDetails""  
	                                    from ""Appointment"" ad
                                        --left join ""Receipt"" R on R.""RespectiveId""=R.""AppointmentId"" and ad.""Status"" <> 'C'  and ad.""Active"" <> false
                                        left join ""Provider"" pr on pr.""ProviderId""= ad.""ProviderId""
                                        left join ""Patient"" pa on Ad.""PatientId""=pa.""PatientId""
                                        left join ""Account"" A on A.""AccountId""=ad.""CreatedBy""
										left join ""Specialization"" sp on sp.""SpecializationId"" = ad.""SpecializationId""
                                        left join ""Role"" Rl on Rl.""RoleId""=A.""RoleId""
                                        left join ""EncounterType"" et on et.""EncounterTypeId""=sp.""EncounterTypeId""
                                        left Join ""VisitType"" vt on vt.""VisitTypeId"" = ad.""VisitTypeId""
                                        --left join ""PayType"" pt on pt.""PayTypeId""=R.""PayTypeId"" 
	                                    {appointmentWhere} and ad.""CreatedDate""::date >='{Convert.ToDateTime(fromDate):yyyy-MM-dd}'::date ";
            response.Appointments = await this.unitOfWork.Current.QueryAsync<AppointmentModel>(appointmentQuery);
            var admissionQuery = $@"select * from ""udf_fetch_Admission_Location""({paramsString})";
            response.Admissions = await this.unitOfWork.Current.QueryAsync<AdmissionModel>(admissionQuery);

            //var pharmacyQuery = $@"SELECT COUNT(*) OVER () AS ""TotalItems"",* from ""udf_pharmacypatientbills_finalreport""({paramsString1})";
            //response.Pharamcy = await this.unitOfWork.Current.QueryAsync<PharmacyBillReportModel>(pharmacyQuery);

            response.Labs = await this.labTransactionService.FetchAddedLabBillAsync(labModel);
            var scanQuery = $@"select count(*) over () as ""TotalItems"",bs.""BookScanAppointmentId"",bs.""PaymentStatus"",bs.""PaymentType"" as ""typeOfPayment"",st.""ScanTestMasterId"",st.""ScanTestName"",st.""Duration"" as ""SlotDuration"",
                    sm.""ScanMachineMasterId"",sm.""MachineName"",bs.""PatientId"",p.""FullName"" as ""PatientName"",p.""UMRNo"",p.""Age"",p.""Gender"",p.""Mobile"",bs.""LocationId"",
                    l.""Name"" as ""LocationName"",bs.""AppointmentTime""::text,bs.""AppointmentEndTime""::text,bs.""AppointmentDate""::text,bs.""Status"",bs.""Amount""
                    from ""BookScanAppointment"" bs
					left join ""ScanTestMaster"" st on st.""ScanTestMasterId""=bs.""ScanTestMasterId""
					left join ""ScanMachineMaster"" sm on sm.""ScanMachineMasterId""=bs.""ScanMachineMasterId""
                    left join ""Patient"" p on p.""PatientId"" = bs.""PatientId""
                    left join ""Location"" l on l.""LocationId"" = bs.""LocationId""
                    {where} and bs.""CreatedDate""::date >='{Convert.ToDateTime(fromDate):yyyy-MM-dd}'::date
                    order by bs.""CreatedDate"" desc";
            response.Scan = await this.unitOfWork.Current.QueryAsync<FetchBookScanAppointment>(scanQuery);
            var otWhere = $@"where 1=1 and ot.""PatientId""={patientId}";
            var otQuery = $@"select count(*) over () as ""TotalItems"",ot.""OTRegisterId"",ot.""Status"",s.""Duration"",
                    ot.""PatientId"",p.""FullName"" as ""PatientName"",p.""UMRNo"",p.""Age"",p.""Gender"",p.""Mobile"",ot.""LocationId"",
                    l.""Name"" as ""LocationName"",ot.""SignInDate""::text,ot.""SignOutDate""::text,ot.""Status"",ot.""CreatedDate"",
					pr.""FullName"" ""ProviderName"",ct.""CaseTypeName"",s.""Name"" ""SurgeryName""
                    from ""OTRegister"" ot
					left join ""CaseType"" ct on ct.""CaseTypeId""=ot.""CaseTypeId""
					left join ""Surgery"" s on s.""SurgeryId""=ot.""SurgeryId""
					left join ""Provider"" pr on pr.""ProviderId"" = ot.""ProviderId""
                    left join ""Patient"" p on p.""PatientId""= ot.""PatientId""
                    left join ""Location"" l on l.""LocationId"" = ot.""LocationId""
                    {otWhere} and ot.""CreatedDate""::date >='{Convert.ToDateTime(fromDate):yyyy-MM-dd}'::date
                    order by ot.""CreatedDate"" desc";
            response.OTData = await this.unitOfWork.Current.QueryAsync<OTRegisterFilterModel>(otQuery);
            return response;
        }
    }
}
