namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Domain.Configurations;
    using Domain.Helpers;
    using Domain.Services;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Http;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.SignalR;

    using Newtonsoft.Json;
    using Shared.EntityModels;

    using Hims.Api.Hubs;
    using Hims.Api.Senders;
    using Hims.Shared.Library.Enums;
    using Hims.Domain.Entities;
    using Hims.Domain.Repositories.UnitOfWork;
    using Hims.Domain.Entities.Enums;
    using System.Web;
    using Hims.Api.Helper;
    using AutoMapper;
    using Hims.Shared.DataFilters;
    using Hims.Api.Models.Appointment;
    using Hims.Shared.UserModels.Pharmacy;
    using Hims.Shared.UserModels.Labs;
    using Hims.Shared.UserModels.Scan.ScanAppointment;
    using Hims.Shared.UserModels.Receipt;
    using Hims.Api.Models.Patient;
    using Hims.Infrastructure.Services;

    /// <summary>
    /// The payment controller.
    /// </summary>
    public class PaymentController : Controller
    {
        /// <summary>
        /// The appointment services.
        /// </summary>
        private readonly IAppointmentService appointmentsServices;

        /// <summary>
        /// The account session services.
        /// </summary>
        private readonly IAccountSessionService accountSessionServices;

        /// <summary> The push notification helper.</summary>
        private readonly IPushNotificationHelper pushNotificationHelper;

        /// <summary>
        /// The appointment log services.
        /// </summary>
        private readonly IAppointmentLogService appointmentLogServices;

        /// <summary>
        /// The pay u configuration.
        /// </summary>
        private readonly IPayUConfiguration payUConfiguration;

        /// <summary>
        /// The salucro configuration.
        /// </summary>
        private readonly ISalucroConfiguration salucroConfiguration;

        /// <summary>
        /// The AES helper.
        /// </summary>
        private readonly IAESHelper aesHelper;

        /// <summary>
        /// The whats application SMS sender
        /// </summary>
        private readonly IWhatsAppSMSSender whatsAppSMSSender;

        /// <summary>
        /// The sms sender.
        /// </summary>
        private readonly ISMSSender smsSender;

        /// <summary>
        /// The email sender.
        /// </summary>
        private readonly IEmailSender emailSender;

        /// <summary>
        /// The appointment exception log services.
        /// </summary>
        private readonly IAppointmentExceptionLogService appointmentExceptionLogServices;

        /// <summary>
        /// The hub context.
        /// </summary>
        private readonly IHubContext<CommunicationHub> hubContext;

        /// <summary>
        /// The timeline service.
        /// </summary>
        private readonly ITimelineService timelineService;

        /// <summary>
        /// The timeline service.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// The patient services.
        /// </summary>
        private readonly IPatientService patientServices;

        /// <summary>
        /// The appointment transaction services.
        /// </summary>
        private readonly IAppointmentTransactionService appointmentTransactionService;

        private readonly ISettingService settingService;

        /// <summary>
        /// The queue services.
        /// </summary>
        private readonly IPaymentInitiationLogService paymentInitiationLogService;


        private readonly AppointmentHelper appointmentHelper;

        /// <summary>
        /// The application configuration.
        /// </summary>
        private readonly IApplicationConfiguration applicationConfiguration;

        /// <summary>
        /// The mapper.
        /// </summary>
        private readonly IMapper mapper;

        /// <summary>
        /// The doctor device details services.
        /// </summary>
        private readonly IDoctorDeviceDetailsService doctorDeviceServices;

        /// <summary>
        /// The patient device details services.
        /// </summary>
        private readonly IPatientDeviceDetailsService patientDeviceServices;

        /// <summary>
        /// The patient device details services.
        /// </summary>
        private readonly IVideoCallHistoryService videoHistoryServices;

        /// <summary>
        /// The Web Telemedicine Service.
        /// </summary>
        private readonly IWebTelemedicineService webTelemedicineService;

        /// <summary>
        /// The provider bank account services.
        /// </summary>
        private readonly IProviderBankAccountService providerBankAccountServices;

        /// <summary>
        /// The document helper.
        /// </summary>
        private readonly IDocumentHelper documentHelper;

        /// <summary>
        /// The url shortner helper.
        /// </summary>
        private readonly IURLShortnerHelper uRLShortnerHelper;

        /// <summary>
        /// The patient medication service
        /// </summary>
        private readonly IPatientEncounterService patientEncounterService;

        /// <summary>
        /// the provider service.
        /// </summary>
        private readonly IProviderService providerService;

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

        /// <summary>
        /// The wallet service.
        /// </summary>
        private readonly IWalletService walletService;

        /// <summary>
        /// The payU service.
        /// </summary>
        private readonly IPayUService payUService;

        /// <summary>
        /// The salucro helper.
        /// </summary>
        private readonly ISalucroHelper salucroHelper;

        /// <summary>
        /// The payU helper.
        /// </summary>
        private readonly IPayUHelper payUHelper;

        /// <summary>
        /// The pharmacy service.
        /// </summary>
        private readonly IPharmacyService pharmacyService;

        /// <summary>
        /// The lab transaction service
        /// </summary>
        private readonly ILabTransactionService labTransactionService;

        /// <summary>
        /// The pharmacy service.
        /// </summary>
        private readonly IResourceService resourceService;

        /// <summary>
        /// The pharmacy service.
        /// </summary>
        private readonly IPharmacyLogService pharmacyLogService;

        /// <summary>
        /// The pharmacy service.
        /// </summary>
        private readonly ILabLogService labLogService;

        /// <summary>
        /// The company service.
        /// </summary>
        private readonly ICompanyService companyService;

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

        /// <summary>
        /// The notification service.
        /// </summary>
        private readonly IWebNotificationService webNotificationService;

        /// <summary>
        /// The laboratory department service.
        /// </summary>
        private readonly ILabDepartmentService laboratoryDepartmentService;

        /// <summary>
        /// The labs service.
        /// </summary>
        private readonly ILabsService labsService;

        /// <summary>
        /// The ftp helper.
        /// </summary>
        private readonly IFtpHelper ftpHelper;

        /// <summary>
        /// The scan machine availability services.
        /// </summary>
        private readonly IBookScanAppointmentService bookScanAppointmentService;

        /// <summary>
        /// The scan service.
        /// </summary>
        private readonly IScanLogService scanLogService;

        /// <summary>
        /// The charge category service.
        /// </summary>
        private readonly IChargeModuleService chargeModuleService;

        /// <summary>
        /// The service
        /// </summary>
        private readonly IReceiptService service;

        /// <summary>
        /// The pharmacy request service.
        /// </summary>
        private readonly IPharmacyRequestService pharmacyRequestService;

        /// <summary>
        /// The account services.
        /// </summary>
        private readonly IAccountService accountServices;

        /// <summary>
        /// The patient insurance services.
        /// </summary>
        private readonly IPatientInsuranceService patientInsuranceServices;

        /// <summary>
        /// The patient emergency services.
        /// </summary>
        private readonly IPatientEmergencyService patientEmergencyServices;

        /// <summary>
        /// The FTP upload helper.
        /// </summary>
        private readonly IFtpUploadHelper ftpUploadHelper;

        /// <summary>
        /// The patient document services.
        /// </summary>
        private readonly IPatientDocumentService patientDocumentServices;

        /// <summary>
        /// The lab vacutainer services.
        /// </summary>
        private readonly ILabVacutainerService labVacutainerService;
        private readonly IAdmissionService admissionsServices;

        private readonly IContactDetailsService contactDetailsService;

        private readonly ICallHistoryDataService callOutDataService;
        /// <summary>
        /// Initializes a new instance of the <see cref="PaymentController"/> class.
        /// </summary>
        /// <param name="timelineService">
        /// The timeline Service.
        /// </param>
        /// <param name="appointmentsServices">
        /// The appointment services.
        /// </param>
        /// <param name="aesHelper">
        /// The aes helper.
        /// </param>
        /// <param name="appointmentLogServices">
        /// The appointment log services.
        /// </param>
        /// <param name="payUConfiguration">
        /// The pay u configuration.
        /// </param>
        /// <param name="smsSender">
        /// The sms sender.
        /// </param>
        /// <param name="appointmentExceptionLogServices">
        /// The appointment exception log services.
        /// </param>
        /// <param name="accountSessionServices">
        /// The account session services.
        /// </param>
        /// <param name="pushNotificationHelper">
        /// The push notification helper.
        /// </param>
        /// <param name="emailSender">
        /// The email sender.
        /// </param>
        /// <param name="hubContext">
        /// The hub context.
        /// </param>
        /// <param name="auditLogServices"></param>
        /// <param name="unitOfWork"></param>
        /// <param name="salucroConfiguration"></param>
        /// <param name="patientService"></param>
        /// <param name="appointmentTransactionService"></param>
        /// <param name="settingService"></param>
        /// <param name="paymentInitiationLogService"></param>
        /// <param name="applicationConfiguration"></param>
        /// <param name="mapper"></param>
        /// <param name="doctorDeviceServices"></param>
        /// <param name="patientDeviceServices"></param>
        /// <param name="videoHistoryServices"></param>
        /// <param name="webTelemedicineService"></param>
        /// <param name="providerBankAccountServices"></param>
        /// <param name="documentHelper"></param>
        /// <param name="uRLShortnerHelper"></param>
        /// <param name="patientEncounterService"></param>
        /// <param name="providerService"></param>
        /// <param name="amazonS3Configuration"></param>
        /// <param name="walletService"></param>
        /// <param name="payUService"></param>
        /// <param name="salucroHelper"></param>
        /// <param name="payUHelper"></param>
        /// <param name="pharmacyService"></param>
        /// <param name="resourceService"></param>
        /// <param name="pharmacyLogService"></param>
        /// <param name="labLogService"></param>
        /// <param name="companyService"></param>
        /// <param name="runningEnvironment"></param>
        /// <param name="webNotificationService"></param>
        /// <param name="labTransactionService"></param>
        /// <param name="laboratoryDepartmentService"></param>
        /// <param name="labsService"></param>
        /// <param name="ftpHelper"></param>
        /// <param name="bookScanAppointmentService"></param>
        /// <param name="scanLogService"></param>
        /// <param name="chargeModuleService"></param>
        /// <param name="service"></param>
        /// <param name="pharmacyRequestService"></param>
        /// <param name="whatsAppSMSSender"></param>
        /// <param name="patientServices"></param>
        /// <param name="ftpUploadHelper"></param>
        /// <param name="patientDocumentServices"></param>
        /// <param name="labVacutainerService"></param>
        public PaymentController(ITimelineService timelineService, IAppointmentService appointmentsServices, IAESHelper aesHelper, IAppointmentLogService appointmentLogServices, IPayUConfiguration payUConfiguration, ISMSSender smsSender, IAppointmentExceptionLogService appointmentExceptionLogServices, IAccountSessionService accountSessionServices, IPushNotificationHelper pushNotificationHelper, IEmailSender emailSender, IHubContext<CommunicationHub> hubContext, IAuditLogService auditLogServices, IUnitOfWork unitOfWork, ISalucroConfiguration salucroConfiguration, IPatientService patientService, IAppointmentTransactionService appointmentTransactionService, ISettingService settingService, IPaymentInitiationLogService paymentInitiationLogService, IApplicationConfiguration applicationConfiguration, IMapper mapper, IDoctorDeviceDetailsService doctorDeviceServices, IPatientDeviceDetailsService patientDeviceServices, IVideoCallHistoryService videoHistoryServices, IWebTelemedicineService webTelemedicineService, IProviderBankAccountService providerBankAccountServices, IDocumentHelper documentHelper, IURLShortnerHelper uRLShortnerHelper, IPatientEncounterService patientEncounterService, IProviderService providerService, IAmazonS3Configuration amazonS3Configuration, IWalletService walletService, IPayUService payUService, ISalucroHelper salucroHelper, IPayUHelper payUHelper, IPharmacyService pharmacyService, IResourceService resourceService, IPharmacyLogService pharmacyLogService, ILabLogService labLogService, ICompanyService companyService, IRunningEnvironment runningEnvironment, IWebNotificationService webNotificationService, ILabTransactionService labTransactionService, ILabDepartmentService laboratoryDepartmentService, ILabsService labsService, IFtpHelper ftpHelper, IBookScanAppointmentService bookScanAppointmentService, IScanLogService scanLogService, IChargeModuleService chargeModuleService, IReceiptService service, IPharmacyRequestService pharmacyRequestService, IWhatsAppSMSSender whatsAppSMSSender, IPatientService patientServices, IFtpUploadHelper ftpUploadHelper, IPatientDocumentService patientDocumentServices, ILabVacutainerService labVacutainerService, IAdmissionService admissionsServices, IContactDetailsService contactDetailsService, ICallHistoryDataService callOutDataService)
        {
            this.appointmentsServices = appointmentsServices;
            this.aesHelper = aesHelper;
            this.appointmentLogServices = appointmentLogServices;
            this.payUConfiguration = payUConfiguration;
            this.smsSender = smsSender;
            this.appointmentExceptionLogServices = appointmentExceptionLogServices;
            this.accountSessionServices = accountSessionServices;
            this.pushNotificationHelper = pushNotificationHelper;
            this.emailSender = emailSender;
            this.hubContext = hubContext;
            this.timelineService = timelineService;
            this.auditLogServices = auditLogServices;
            this.unitOfWork = unitOfWork;
            this.salucroConfiguration = salucroConfiguration;
            this.patientServices = patientService;
            this.appointmentTransactionService = appointmentTransactionService;
            this.settingService = settingService;
            this.paymentInitiationLogService = paymentInitiationLogService;
            this.applicationConfiguration = applicationConfiguration;
            this.mapper = mapper;
            this.patientDeviceServices = patientDeviceServices;
            this.doctorDeviceServices = doctorDeviceServices;
            this.videoHistoryServices = videoHistoryServices;
            this.webTelemedicineService = webTelemedicineService;
            this.providerBankAccountServices = providerBankAccountServices;
            this.documentHelper = documentHelper;
            this.uRLShortnerHelper = uRLShortnerHelper;
            this.patientEncounterService = patientEncounterService;
            this.providerService = providerService;
            this.amazonS3Configuration = amazonS3Configuration;
            this.walletService = walletService;
            this.payUService = payUService;
            this.payUHelper = payUHelper;
            this.salucroHelper = salucroHelper;
            this.pharmacyService = pharmacyService;
            this.resourceService = resourceService;
            this.pharmacyLogService = pharmacyLogService;
            this.labLogService = labLogService;
            this.companyService = companyService;
            this.runningEnvironment = runningEnvironment;
            this.webNotificationService = webNotificationService;
            this.labTransactionService = labTransactionService;
            this.laboratoryDepartmentService = laboratoryDepartmentService;
            this.labsService = labsService;
            this.ftpHelper = ftpHelper;
            this.bookScanAppointmentService = bookScanAppointmentService;
            this.scanLogService = scanLogService;
            this.chargeModuleService = chargeModuleService;
            this.service = service;
            this.pharmacyRequestService = pharmacyRequestService;
            this.whatsAppSMSSender = whatsAppSMSSender;
            this.patientServices = patientServices;
            this.ftpUploadHelper = ftpUploadHelper;
            this.patientDocumentServices = patientDocumentServices;
            this.labVacutainerService = labVacutainerService;
            this.contactDetailsService = contactDetailsService;
            this.callOutDataService = callOutDataService;
            appointmentHelper = AppointmentHelper.GetInstance(auditLogServices, appointmentsServices, settingService, pushNotificationHelper, smsSender, emailSender, accountSessionServices, whatsAppSMSSender, unitOfWork);
            this.admissionsServices = admissionsServices;
        }

        /// <summary>
        /// The index.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="IActionResult"/>.
        /// </returns>
        public async Task<IActionResult> Index(string id)
        {
            try
            {
                if (string.IsNullOrEmpty(id))
                {
                    return this.View("_Error");
                }

                var decrypted = this.aesHelper.Decode(id);
                var appointmentLogId = Convert.ToInt32(decrypted);
                var appointmentLog = await this.appointmentLogServices.FindAsync(appointmentLogId);
                if (appointmentLog == null || appointmentLog.AppointmentLogId == 0)
                {
                    return this.View("_Error");
                }

                var productInfo = $"Appointment with Dr.{appointmentLog.ProviderName}";
                this.ViewBag.ProductInfo = productInfo;

                var transactionId = await this.appointmentTransactionService.GetATransactionId();
                this.ViewBag.TransactionId = transactionId;

                var hashString = this.payUConfiguration.Key + "|" + transactionId + "|" + appointmentLog.Total + "|" + productInfo + "|" + appointmentLog.PatientFirstName + "|" + appointmentLog.PatientEmail + "|" + appointmentLog.AppointmentLogId + "||||||||||" + this.payUConfiguration.Salt;
                this.ViewBag.Hash = PaymentHelper.GenerateHash(hashString);

                return this.View(new Tuple<AppointmentLogModel, IPayUConfiguration>(appointmentLog, this.payUConfiguration));
            }
            catch
            {
                return this.View("_Error");
            }
        }

        /// <summary>
        /// The index.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="IActionResult"/>.
        /// </returns>
        public async Task<IActionResult> InitiatePatientPayment(string id)
        {
            try
            {
                if (string.IsNullOrEmpty(id))
                {
                    return this.View("_Error");
                }

                var decrypted = this.aesHelper.Decode(id);
                var tId = Convert.ToInt32(decrypted);
                var patientDetails = new PatientModel();
                var processing_id = await this.appointmentTransactionService.GetATransactionId();
                var hashString = this.salucroConfiguration.User + "|" + this.salucroConfiguration.Key + "|" + processing_id + "|" + this.salucroConfiguration.MId + "|" + this.salucroConfiguration.SecretKey;
                this.ViewBag.CheckSumHash = Convert.ToBase64String(HttpUtility.UrlEncodeToBytes(Encoding.ASCII.GetBytes(PaymentHelper.GenerateCheckSumHash(hashString))));
                this.ViewBag.ProcessingId = processing_id;
                //custom-custom6 we can use
                this.ViewBag.Custom = tId;
                var paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);
                dynamic data = JsonConvert.DeserializeObject(paymentInitiationLog.TableData);
                int patientId = data["patientId"];
                decimal amount = data["totalAmount"];
                decimal patientRegistrationCharges = 0;
                patientRegistrationCharges = data["patientTotal"] ?? 0;

                if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                {
                    return this.View("_Error");
                }
                patientDetails = await this.patientServices.FindAsync(patientId);
                amount = patientDetails.PaymentStatus == false ? amount + patientRegistrationCharges : amount;

                this.ViewBag.PatientEmail = patientDetails.Email;
                this.ViewBag.PatientMobile = patientDetails.Mobile;
                this.ViewBag.Amount = amount;
                this.ViewBag.PatientName = patientDetails.FullName;
                this.ViewBag.PatientUmrNo = patientDetails.UMRNo;
                this.ViewBag.Custom1 = paymentInitiationLog.PaymentModuleId;
                return this.View(this.salucroConfiguration);
            }
            catch (Exception)
            {
                return this.View("_Error");
            }
        }

        /// <summary>
        /// The index.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <param name="mode"></param>
        /// <param name="modifiedBy"></param>
        /// <param name="reason"></param>
        /// <param name="varyAmount"></param>
        /// <param name="isMultiPayments"></param>
        /// <returns>
        /// The <see cref="IActionResult"/>.
        /// </returns>
        public async Task<IActionResult> Initiate(string id, string mode, int? modifiedBy, string reason, decimal? varyAmount, bool? isMultiPayments)
        {
            try
            {
                if (string.IsNullOrEmpty(id))
                {
                    return this.View("_Error");
                }

                var decrypted = this.aesHelper.Decode(id);
                var tId = Convert.ToInt32(decrypted);
                var patientDetails = new PatientModel();
                var processing_id = await this.appointmentTransactionService.GetATransactionId();
                var hashString = this.salucroConfiguration.User + "|" + this.salucroConfiguration.Key + "|" + processing_id + "|" + this.salucroConfiguration.MId + "|" + this.salucroConfiguration.SecretKey;
                this.ViewBag.CheckSumHash = Convert.ToBase64String(HttpUtility.UrlEncodeToBytes(Encoding.ASCII.GetBytes(PaymentHelper.GenerateCheckSumHash(hashString))));
                this.ViewBag.ProcessingId = processing_id;
                //custom-custom6 we can use
                this.ViewBag.Custom = tId;
                if (mode == "Payment")
                {
                    var paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);
                    var userDetails = await this.unitOfWork.Accounts.FindAsync(x => x.AccountId == paymentInitiationLog.CreatedBy);
                    var userName = userDetails.FullName.Replace(" ", "").Replace("(","").Replace(")","").Trim() + userDetails.AccountId;
                    dynamic data = JsonConvert.DeserializeObject(paymentInitiationLog.TableData);
                    int admissionId = data["id"] ?? 0;
                    int patientId = data["patientId"] != null ? data["patientId"] : 0;
                    int payTypeId = data["payTypeId"];
                    decimal amount = data["totalAmount"] ?? 0;
                    string mobile = "";
                    decimal patientRegistrationCharges = 0;
                    patientRegistrationCharges = data["patientTotal"] ?? 0;
                    string fullName = "";
                    string umrNo = "";
                    string module = data["category"];
                    if (patientId == 0)
                    {
                        mobile = data["mobile"];
                        string firstName = data["firstName"];
                        string middleName = data["middleName"];
                        string lastName = data["lastName"];
                        string ptName = data["fullName"] ?? null;
                        fullName = string.IsNullOrEmpty(ptName) ? CoreFilter.FullName(firstName, middleName, lastName) : ptName;
                        umrNo = mobile != null ? mobile : "UnIdentified";
                    }
                    if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                    {
                        return this.View("_Error");
                    }
                    if (patientId != 0)
                    {
                        patientDetails = await this.patientServices.FindAsync(patientId);
                        //amount = patientDetails.PaymentStatus == false ? amount + patientRegistrationCharges : amount;
                    }
                    var payType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == payTypeId);
                    this.ViewBag.PayMode = payType.PayTypeValue;
                    //this.ViewBag.Amount = varyAmount > 0 ? varyAmount : patientId != 0 ? amount : amount + patientRegistrationCharges;
                    this.ViewBag.Amount = varyAmount > 0 ? varyAmount : amount > 0 ? amount : patientRegistrationCharges;
                    this.ViewBag.PatientName = patientId != 0 ? patientDetails.FullName : fullName;
                    this.ViewBag.PatientUmrNo = patientId != 0 ? patientDetails.UMRNo : umrNo;
                    this.ViewBag.Custom1 = paymentInitiationLog.PaymentModuleId;
                    this.ViewBag.Custom4 = mode;
                    this.ViewBag.Custom5 = admissionId;
                    this.ViewBag.Custom6 = module;
                    this.ViewBag.Custom2 = isMultiPayments == true ? isMultiPayments : false;
                    this.ViewBag.Custom3 = data.typeOfPayment;
                    this.ViewBag.UserName = userName;
                    return this.View(this.salucroConfiguration);
                }
                else if (mode == "Refund")
                {
                    var paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);
                    switch (paymentInitiationLog.PaymentModuleId)
                    {

                        case 3:
                            var data = JsonConvert.DeserializeObject<PharmacySaleReturnBillModel>(paymentInitiationLog.TableData);
                            if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                            {
                                return this.View("_Error");
                            }
                            var transaction = await this.unitOfWork.AppointmentTransactions.FindAsync(x => x.AppointmentId == data.PharmacySaleHeaderId && x.ReceiptTypeId == 1 && x.ReceiptAreaTypeId == 1);
                            var saleHeader = await this.unitOfWork.PharmacySaleHeaders.FindAsync(x => x.PharmacySaleHeaderId == data.PharmacySaleHeaderId);
                            patientDetails = await this.patientServices.FindAsync((int)saleHeader.PatientId);
                            var payType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == saleHeader.PayTypeId);

                            if (saleHeader.PayTypeId == 4 || saleHeader.PayTypeId == 18)
                            {
                                this.ViewBag.PayMode = "online-refund";
                            }
                            else if (saleHeader.PayTypeId == 10)
                            {
                                this.ViewBag.PayMode = "cash-cashdrawer";
                            }
                            else
                            {
                                this.ViewBag.PayMode = payType.PayTypeValue;
                            }

                            this.ViewBag.TransactionId = transaction.TransactionId;
                            this.ViewBag.Amount = transaction.SettledAmount;
                            this.ViewBag.PatientName = patientDetails.FullName;
                            this.ViewBag.PatientUmrNo = patientDetails.UMRNo;
                            this.ViewBag.Custom3 = paymentInitiationLog.PaymentModuleId;
                            this.ViewBag.Custom4 = mode;
                            this.ViewBag.Custom5 = 0;
                            this.ViewBag.UserName = this.salucroConfiguration.UserName;
                            return this.View(this.salucroConfiguration);

                        case 4:
                            var labsData = JsonConvert.DeserializeObject<LabBookingModel>(paymentInitiationLog.TableData);
                            if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                            {
                                return this.View("_Error");
                            }
                            var labsTransaction = await this.unitOfWork.AppointmentTransactions.FindAsync(x => x.AppointmentId == labsData.NewLabBookingHeaderId && x.ReceiptTypeId == 1 && x.ReceiptAreaTypeId == 8);
                            var labsSaleHeader = await this.unitOfWork.NewLabBookingHeaders.FindAsync(x => x.NewLabBookingHeaderId == labsData.NewLabBookingHeaderId);
                            patientDetails = await this.patientServices.FindAsync((int)labsSaleHeader.PatientId);
                            var labsPayType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == labsSaleHeader.PayTypeId);

                            if (labsSaleHeader.PayTypeId == 4 || labsSaleHeader.PayTypeId == 18)
                            {
                                this.ViewBag.PayMode = "online-refund";
                            }
                            else if (labsSaleHeader.PayTypeId == 10)
                            {
                                this.ViewBag.PayMode = "cash-cashdrawer";
                            }
                            else
                            {
                                this.ViewBag.PayMode = labsPayType.PayTypeValue;
                            }

                            this.ViewBag.TransactionId = labsTransaction.TransactionId;
                            this.ViewBag.Amount = labsTransaction.SettledAmount;
                            this.ViewBag.PatientName = patientDetails.FullName;
                            this.ViewBag.PatientUmrNo = patientDetails.UMRNo;
                            this.ViewBag.Custom3 = paymentInitiationLog.PaymentModuleId;
                            this.ViewBag.Custom4 = mode;
                            this.ViewBag.Custom5 = 0;
                            this.ViewBag.UserName = this.salucroConfiguration.UserName;
                            return this.View(this.salucroConfiguration);

                        case 7:
                        case 5:
                            var scanAppointmentsData = JsonConvert.DeserializeObject<BookScanAppointment>(paymentInitiationLog.TableData);
                            if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                            {
                                return this.View("_Error");
                            }
                            var scanAppointmentTransaction = await this.unitOfWork.AppointmentTransactions.FindAsync(x => x.AppointmentId == scanAppointmentsData.BookScanAppointmentId && x.ReceiptTypeId == 1 && x.ReceiptAreaTypeId == 10);
                            var scanAppointment = await this.unitOfWork.BookScanAppointments.FindAsync(x => x.BookScanAppointmentId == scanAppointmentsData.BookScanAppointmentId);
                            var scanAppointmentPatientDetails = await this.patientServices.FindAsync((int)scanAppointment.PatientId);
                            var scanPayType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == scanAppointment.PayTypeId);

                            if (scanAppointment.PayTypeId == 4 || scanAppointment.PayTypeId == 18)
                            {
                                this.ViewBag.PayMode = "online-refund";
                            }
                            else if (scanAppointment.PayTypeId == 10)
                            {
                                this.ViewBag.PayMode = "cash-cashdrawer";
                            }
                            else
                            {
                                this.ViewBag.PayMode = scanPayType.PayTypeValue;
                            }

                            this.ViewBag.TransactionId = scanAppointmentTransaction.TransactionId;
                            this.ViewBag.Amount = scanAppointmentTransaction.SettledAmount;
                            this.ViewBag.PatientName = scanAppointmentPatientDetails.FullName;
                            this.ViewBag.PatientUmrNo = scanAppointmentPatientDetails.UMRNo;
                            this.ViewBag.Custom3 = paymentInitiationLog.PaymentModuleId;
                            this.ViewBag.Custom4 = mode;
                            this.ViewBag.Custom5 = 0;
                            this.ViewBag.UserName = this.salucroConfiguration.UserName;
                            return this.View(this.salucroConfiguration);

                        case 6:
                            var refundReceipt = JsonConvert.DeserializeObject<InsertModel>(paymentInitiationLog.TableData);
                            refundReceipt.AdmissionId = Convert.ToInt32(refundReceipt.Id);
                            if (paymentInitiationLog == null || paymentInitiationLog.PaymentInitiationLogId == 0)
                            {
                                return this.View("_Error");
                            }
                            var admission = await this.unitOfWork.Admission.FindAsync(x => x.AdmissionId == refundReceipt.AdmissionId);
                            var receiptPatientDetails = await this.patientServices.FindAsync(admission.PatientId);
                            var admissionReceipt = await this.unitOfWork.Receipt.FindAsync(x => x.AdmissionId == refundReceipt.AdmissionId && x.ReceiptTypeId == ReceiptType.Cash && x.ReceiptAreaTypeId == ReceiptAreaType.AdmissionReceipt && x.Active == true && x.Cost > refundReceipt.Cost && x.IsSalucroAdmissionReceipt == true);
                            var admissionReceiptTransaction = await this.unitOfWork.AppointmentTransactions.FindAsync(x => x.AppointmentId == admissionReceipt.ReceiptId && x.ReceiptTypeId == 1 && x.ReceiptAreaTypeId == 12);
                            var receiptPayType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == admissionReceipt.PayTypeId);

                            if (admissionReceipt.PayTypeId == 4 || admissionReceipt.PayTypeId == 18)
                            {
                                this.ViewBag.PayMode = "online-refund";
                            }
                            else if (admissionReceipt.PayTypeId == 10)
                            {
                                this.ViewBag.PayMode = "cash-cashdrawer";
                            }
                            else
                            {
                                this.ViewBag.PayMode = receiptPayType.PayTypeValue;
                            }

                            this.ViewBag.TransactionId = admissionReceiptTransaction.TransactionId;
                            this.ViewBag.Amount = admissionReceiptTransaction.SettledAmount;
                            this.ViewBag.PatientName = receiptPatientDetails.FullName;
                            this.ViewBag.PatientUmrNo = receiptPatientDetails.UMRNo;
                            this.ViewBag.Custom3 = paymentInitiationLog.PaymentModuleId;
                            this.ViewBag.Custom4 = mode;
                            this.ViewBag.Custom5 = refundReceipt.AdmissionId;
                            this.ViewBag.UserName = this.salucroConfiguration.UserName;
                            return this.View(this.salucroConfiguration);
                    }
                    return this.View();
                }
                else
                {
                    var appointment = await this.appointmentsServices.FindAsync(tId);
                    var transaction = await this.appointmentTransactionService.FetchAsync(tId);
                    if (appointment == null || appointment.AppointmentId == 0)
                    {
                        return this.View("_Error");
                    }

                    patientDetails = await this.patientServices.FindAsync(appointment.PatientId);
                    var payType = await this.unitOfWork.PayTypes.FindAsync(m => m.PayTypeId == appointment.PayTypeId);

                    if (appointment.PayTypeId == 4 || appointment.PayTypeId == 18)
                    {
                        this.ViewBag.PayMode = "online-refund";
                    }
                    else if (appointment.PayTypeId == 10)
                    {
                        this.ViewBag.PayMode = "cash-cashdrawer";
                    }
                    else
                    {
                        this.ViewBag.PayMode = payType.PayTypeValue;
                    }

                    this.ViewBag.TransactionId = transaction.TransactionId;
                    this.ViewBag.Amount = transaction.SettledAmount;
                    this.ViewBag.PatientName = patientDetails.FullName;
                    this.ViewBag.PatientUmrNo = patientDetails.UMRNo;
                    this.ViewBag.Custom1 = modifiedBy;
                    this.ViewBag.Custom2 = reason;
                    this.ViewBag.Custom3 = 0;
                    this.ViewBag.Custom4 = mode;
                    this.ViewBag.Custom5 = 0;
                    this.ViewBag.UserName = this.salucroConfiguration.UserName;
                    return this.View(this.salucroConfiguration);
                }
            }
            catch (Exception e)
            {
                return this.View("_Error");
            }
        }

        /// <summary>
        /// The Payment.
        /// </summary>
        /// <param name="collection">
        /// The collection.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1126:PrefixCallsCorrectly", Justification = "Reviewed. Suppression is OK here.")]
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> SuccessAsync(IFormCollection collection)
        {
            var transactionId = collection["txnid"];
            var appointmentLogId = Convert.ToInt32(collection["udf1"]);

            try
            {
                if (collection["status"] == "success")
                {
                    var bankReference = collection["bank_ref_num"];
                    var bankCode = collection["bankcode"];
                    var paymentId = Convert.ToInt64(collection["payuMoneyId"]);
                    if (paymentId == 0)
                    {
                        paymentId = Convert.ToInt64(collection["mihPayId"]);
                    }

                    var transaction = ToJson(collection);
                    var (appointmentId, isExists, errorMessage) = await this.appointmentsServices.AddAsync(appointmentLogId, transactionId, transaction, bankReference, bankCode, paymentId, 0, null);
                    if (!string.IsNullOrEmpty(errorMessage))
                    {
                        await this.appointmentExceptionLogServices.LogAsync(new AppointmentExceptionLogModel
                        {
                            AppointmentId = null,
                            AppointmentLogId = appointmentLogId,
                            PaymentTransactionId = transactionId,
                            PaymentStatus = true,
                            ExceptionMessage = errorMessage,
                            StackTrace = null
                        });
                    }

                    switch (appointmentId)
                    {
                        case -1:
                            return this.View(this.payUConfiguration.RedirectFailureLink);
                        case 0:
                            return this.View(this.payUConfiguration.RedirectFailureLink);
                    }

                    var appointment = await this.appointmentsServices.FindAsync(appointmentId);

                    if (!isExists)
                    {
                        var timespan = new TimeSpan(appointment.AppointmentTime.Hours, appointment.AppointmentTime.Minutes, appointment.AppointmentTime.Seconds);
                        var time = DateTime.Today.Add(timespan);
                        var displayTime = time.ToString("hh:mm tt");

                        // Sending Message
                        await this.smsSender.SendPaymentMessageAsync(appointment, displayTime);

                        // end 

                        // Sending push notifications to Provider and Patient
                        if (appointment.EnableMobileNotifications == true)
                        {
                            var accountSessionProviderModel = await this.accountSessionServices.FetchDeviceTokenAsync(appointment.ProviderId, Roles.Provider);
                            var sessionProviderModel = accountSessionProviderModel as AccountSessionModel[] ?? accountSessionProviderModel.ToArray();
                            if (sessionProviderModel.Any())
                            {
                                var deviceTokenForProviderAndroid = sessionProviderModel.Where(d => d.DeviceType == 2).Select(s => s.DeviceToken).ToList();
                                var deviceTokenForProviderIOS = sessionProviderModel.Where(d => d.DeviceType == 3).Select(s => s.DeviceToken).ToList();

                                if (deviceTokenForProviderAndroid.Any())
                                {
                                    await this.pushNotificationHelper.SendAltAsync(
                                        "Hims",
                                        appointment.PatientName + " patient booked an Appointment with you on Date:" + appointment.AppointmentDate.ToString("dd MMMM yyyy") + " Time: " + displayTime + " ",
                                        "Appointment",
                                        deviceTokenForProviderAndroid,
                                        new List<string>(),
                                        appointment.ProviderName,
                                        appointment.AppointmentDate.ToString("MM/dd/yyyy") + " " + displayTime);
                                }

                                if (deviceTokenForProviderIOS.Any())
                                {
                                    await this.pushNotificationHelper.SendAltAsync(
                                        "Hims",
                                        appointment.PatientName + " patient booked an Appointment with you on Date:" + appointment.AppointmentDate.ToString("dd MMMM yyyy") + " Time: " + displayTime + " ",
                                        "Appointment",
                                        new List<string>(),
                                        deviceTokenForProviderIOS,
                                        appointment.ProviderName,
                                        appointment.AppointmentDate.ToString("MM/dd/yyyy") + " " + displayTime);
                                }
                            }
                        }

                        var accountSessionPatientModel = await this.accountSessionServices.FetchDeviceTokenAsync(appointment.PatientId, Roles.Patient);
                        var accountSessionModels = accountSessionPatientModel as AccountSessionModel[] ?? accountSessionPatientModel.ToArray();
                        if (accountSessionModels.Any())
                        {
                            var deviceTokenForProviderAndroid = accountSessionModels.Where(d => d.DeviceType == 2).Select(s => s.DeviceToken).ToList();
                            var deviceTokenForProviderIOS = accountSessionModels.Where(d => d.DeviceType == 3).Select(s => s.DeviceToken).ToList();

                            if (appointment.ProviderName != null)
                            {
                                if (deviceTokenForProviderAndroid.Any())
                                {
                                    _ = await this.pushNotificationHelper.SendAltAsync(
                                            "Hims",
                                            "Appointment booked with DR. " + appointment.ProviderName.ToUpper() + " on Date:" + appointment.AppointmentDate.ToString("dd MMMM yyyy") + " Time: " + displayTime + " ",
                                            "Appointment",
                                            deviceTokenForProviderAndroid,
                                            new List<string>(),
                                            appointment.ProviderName,
                                            appointment.AppointmentDate.ToString("MM/dd/yyyy") + " " + displayTime);
                                }

                                if (deviceTokenForProviderIOS.Any())
                                {
                                    _ = await this.pushNotificationHelper.SendAltAsync(
                                            "Hims",
                                            "Appointment booked with DR. " + appointment.ProviderName.ToUpper() + " on Date:" + appointment.AppointmentDate.ToString("dd MMMM yyyy") + " Time: " + displayTime + " ",
                                            "Appointment",
                                            new List<string>(),
                                            deviceTokenForProviderIOS,
                                            appointment.ProviderName,
                                            appointment.AppointmentDate.ToString("MM/dd/yyyy") + " " + displayTime);
                                }
                            }
                        }

                        // end
                        if (!string.IsNullOrEmpty(appointment.PatientEmail))
                        {
                            await this.emailSender.SendBookAppointmentMailAsync(
                                appointment.PatientEmail,
                                appointment.PatientName,
                                "Patient",
                                appointment.ProviderName,
                                appointment.AppointmentDate.ToString("dd MMMM yyyy") + ", " + displayTime,
                                "booked");
                        }

                        if (!string.IsNullOrEmpty(appointment.ProviderEmail) && appointment.EnableEmailAlerts == true)
                        {
                            await this.emailSender.SendBookAppointmentMailAsync(
                                appointment.ProviderEmail,
                                appointment.PatientName,
                                "Provider",
                                appointment.ProviderName,
                                appointment.AppointmentDate.ToString("dd MMMM yyyy") + ", " + displayTime,
                                "booked");
                        }
                    }

                    await this.timelineService.LogAsync(new TimelineModel
                    {
                        PatientId = appointment.PatientId,
                        AppointmentId = appointmentId,
                        TimelineActionId = TimelineAction.AppointmentAdded,
                        CreatedBy = appointment.CreatedBy,
                        Description = $"Appointment has been booked"
                    });
                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = appointment.CreatedBy,
                        LogTypeId = (int)LogTypes.Appointments,
                        LogFrom = (int)AccountType.Patient,
                        LogDate = DateTime.UtcNow,
                        LogDescription = $"Patient Appointment has been booked With Dr.{appointment.ProviderName}.<br>" +
                        $"AppointmentId: {appointment.AppointmentId}.<br>Appointment No: {appointment.AppointmentNo}.<br>Patient: {appointment.PatientName}.<br>TransactionId: {transactionId}.<br>Bank Reference: {bankReference}.<br>Bank Code: {bankCode}.<br>Payment Id: {paymentId.ToString()}.<br>Status: {collection["status"]}."
                    };
                    var refreshModel = new CommunicationMessage
                    {
                        Content = appointment?.AppointmentNo,
                        MainId = appointment?.ProviderId ?? 0,
                        Type = CommunicationType.AppointmentAddRefresh
                    };
                    await this.hubContext.Clients.All.SendAsync("Communication", refreshModel).ConfigureAwait(false);
                    await this.auditLogServices.LogAsync(auditLogModel);

                    var receipt = new Receipt
                    {
                        AppointmentId = appointment.AppointmentId,
                        Active = true,
                        Cost = Convert.ToDouble(collection["amount"]),
                        CreatedBy = appointment.CreatedBy,
                        CreatedDate = DateTime.Now,
                        IsAdvance = false,
                        IsRefunded = false,
                        PayTypeId = Convert.ToInt32(collection["udf2"]),
                        ReceiptTypeId = ReceiptType.Cash,
                        IsAppointmentReceipt = true
                    };

                    await this.unitOfWork.Receipt.InsertAsync(receipt);

                    return this.Redirect(this.payUConfiguration.RedirectSuccessLink);
                    //return this.Redirect(this.payUConfiguration.RedirectSuccessLink + this.aesHelper.Encode(appointmentId.ToString()));
                }

                // await this.appointmentLogServices.DeleteAsync(appointmentLogId);
                await this.appointmentExceptionLogServices.LogAsync(new AppointmentExceptionLogModel
                {
                    AppointmentId = null,
                    AppointmentLogId = appointmentLogId,
                    PaymentTransactionId = transactionId,
                    PaymentStatus = false,
                    ExceptionMessage = collection["error"] + " : " + collection["error_Message"],
                    StackTrace = null
                });
                return this.View(this.payUConfiguration.RedirectFailureLink);
            }
            catch (Exception exception)
            {
                await this.appointmentExceptionLogServices.LogAsync(new AppointmentExceptionLogModel
                {
                    AppointmentId = null,
                    AppointmentLogId = appointmentLogId,
                    PaymentTransactionId = transactionId,
                    PaymentStatus = false,
                    ExceptionMessage = exception.Message,
                    StackTrace = exception.StackTrace
                });
                return this.View(this.payUConfiguration.RedirectFailureLink);
            }
        }

        /// <summary>
        /// The Payment failure.
        /// </summary>
        /// <param name="collection">
        /// The collection.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> FailureAsync(IFormCollection collection)
        {
            var transactionId = collection["txnid"];
            var appointmentLogId = Convert.ToInt32(collection["udf1"]);

            //await this.appointmentLogServices.DeleteAsync(appointmentLogId);

            await this.appointmentExceptionLogServices.LogAsync(new AppointmentExceptionLogModel
            {
                AppointmentId = null,
                AppointmentLogId = appointmentLogId,
                PaymentTransactionId = transactionId,
                PaymentStatus = false,
                ExceptionMessage = collection["error"] + " : " + collection["error_Message"] + " : " + collection["field9"],
                StackTrace = null
            });
            return this.Redirect(this.payUConfiguration.RedirectFailureLink);
        }

        /// <summary>
        /// The Payment failure.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<IActionResult> ResponseSalucro()
        {
            dynamic item = JsonConvert.DeserializeObject(Request.Form["responseToken"]);
            string transactionId = item["processing_id"];
            int salucroStatusCode = item["status_code"];
            //success or pending transaction from salucro
            if (salucroStatusCode == 1200 || salucroStatusCode == 1201)
            {
                // Save Request.Form in PaymentResponseLog with false
                var paymentResponseLog = new PaymentResponseLog
                {
                    JsonData = JsonConvert.SerializeObject(item),
                    IsSuccess = false,
                    CreatedDate = DateTime.Now
                };
                await this.unitOfWork.PaymentResponseLog.InsertAsync(paymentResponseLog);
                try
                {
                    PharmacyController pharmacyController = new PharmacyController(
                                     pharmacyService,
                                     resourceService,
                                     aesHelper,
                                     pharmacyLogService,
                                     labLogService,
                                     companyService,
                                     emailSender,
                                     runningEnvironment,
                                    webNotificationService,
                                    whatsAppSMSSender,
                                    patientServices,
                                    settingService
                                    );
                    LabTransactionController labTransactionController = new LabTransactionController(labLogService, labTransactionService, webNotificationService, aesHelper, whatsAppSMSSender, resourceService, ftpUploadHelper, runningEnvironment, patientServices, pushNotificationHelper, accountSessionServices,settingService);
                    LabsController labsController = new LabsController(labLogService, laboratoryDepartmentService, labsService, aesHelper, ftpHelper, chargeModuleService, whatsAppSMSSender, resourceService, labVacutainerService, pushNotificationHelper, accountSessionServices, settingService);
                    AppointmentsController appointmentsController = new AppointmentsController(
                                 appointmentsServices,
                                 webNotificationService,
                                 applicationConfiguration,
                                 patientServices,
                                 aesHelper,
                                 appointmentLogServices,
                                 mapper,
                                 smsSender,
                                 doctorDeviceServices,
                                 patientDeviceServices,
                                 videoHistoryServices,
                                 pushNotificationHelper,
                                 accountSessionServices,
                                 webTelemedicineService,
                                 hubContext,
                                 emailSender,
                                 payUConfiguration,
                                 timelineService,
                                 auditLogServices,
                                 documentHelper,
                                 providerBankAccountServices,
                                 uRLShortnerHelper,
                                 amazonS3Configuration,
                                 patientEncounterService,
                                 providerService,
                                 settingService,
                                 salucroConfiguration,
                                 appointmentTransactionService,
                                 walletService,
                                 payUService,
                                 salucroHelper,
                                 payUHelper,
                                 unitOfWork,
                                 paymentInitiationLogService,
                                 runningEnvironment,
                                 ftpUploadHelper,
                                 patientDocumentServices,
                                 patientInsuranceServices,
                                 patientEmergencyServices,
                                 scanLogService,
                                 whatsAppSMSSender,
                                 admissionsServices,
                                 contactDetailsService,
                                 callOutDataService);

                    BookScanAppointmentController bookScanAppointmentController = new BookScanAppointmentController(
                        bookScanAppointmentService,
                        aesHelper,
                        patientServices,
                        scanLogService,
                        whatsAppSMSSender,
                        unitOfWork,
                        webNotificationService,
                        documentHelper,
                        ftpUploadHelper,
                        runningEnvironment,
                        auditLogServices,
                        settingService
                    );
                    PatientsController patientsController = new PatientsController(
                  patientServices, mapper, aesHelper, patientInsuranceServices, patientEmergencyServices,
                   documentHelper, accountServices, smsSender, emailSender, applicationConfiguration, uRLShortnerHelper, auditLogServices,
                   unitOfWork, ftpHelper, ftpUploadHelper, runningEnvironment, patientDocumentServices, whatsAppSMSSender, settingService
                   );

                    ReceiptController receiptController = new ReceiptController(
                                     service, auditLogServices, pharmacyRequestService);

                    var transaction = JsonConvert.SerializeObject(item);
                    int tId = item["custom"];
                    string salucroTransactionId = item["transaction_id"];
                    var amountPaid = item.accounts.amount;

                    var otherTransactions = await this.appointmentsServices.FetchTransactionDataAsync(tId);
                    if (otherTransactions != null && otherTransactions.Count() > 0)
                    {
                        dynamic paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);
                        dynamic tableData = JsonConvert.DeserializeObject(paymentInitiationLog.TableData);
                        int createdBy = tableData.createdBy;
                        string paymentNumber = tableData.paymentNumber;
                        int locationId = tableData.locationId;
                        int patientId = tableData.patientId != null ? tableData.patientId : otherTransactions.ToList()[0].PatientId;
                        int payTypeId = tableData.payTypeId;
                        //appointmentModel.PatientRegistrationAmount = appointmentModel.Charges != null ? appointmentModel.Charges : appointmentModel.PatientRegistrationAmount;
                        var model = new AppointmentModel()
                        {
                            TotalAmount = amountPaid,
                            PaymentStatus = salucroStatusCode == 1200 ? true : false,
                            TransactionId = transactionId,
                            Transaction = transaction,
                            SalucroStatusCode = salucroStatusCode,
                            SalucroTransactionId = salucroTransactionId,
                            AppointmentId = otherTransactions.ToList()[0].AppointmentId,
                            ModuleType = paymentInitiationLog.PaymentModuleId,
                            CreatedBy = createdBy,
                            PayTypeId = payTypeId,
                            PaymentNumber = paymentNumber,
                            LocationId = locationId,
                            PatientId = patientId
                        };
                        await appointmentsController.UpdatePartialPayment(model);

                        return this.View();
                    }

                    if (salucroTransactionId.Contains("re"))
                    {
                        int moduleId = item["custom3"];
                        if (moduleId != 0)
                        {
                            dynamic paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);
                            switch (moduleId)
                            {
                                case 1: break;
                                case 2: break;
                                case 3:
                                    var pharmacyReturnModel = (PharmacySaleReturnBillModel)JsonConvert.DeserializeObject<PharmacySaleReturnBillModel>(paymentInitiationLog.TableData);
                                    pharmacyReturnModel.PaymentInitiationLogId = (int)item["custom"];
                                    pharmacyReturnModel.TransactionId = transactionId;
                                    pharmacyReturnModel.Transaction = transaction;
                                    pharmacyReturnModel.SalucroStatusCode = salucroStatusCode;
                                    pharmacyReturnModel.SalucroTransactionId = salucroTransactionId;
                                    await pharmacyController.ReturnAsyncHelper(pharmacyReturnModel);
                                    break;
                                case 4:
                                    var labReturnModel = (LabBookingModel)JsonConvert.DeserializeObject<LabBookingModel>(paymentInitiationLog.TableData);
                                    labReturnModel.PaymentInitiationLogId = tId;
                                    labReturnModel.TransactionId = transactionId;
                                    labReturnModel.Transaction = transaction;
                                    labReturnModel.SalucroStatusCode = salucroStatusCode;
                                    labReturnModel.SalucroTransactionId = salucroTransactionId;
                                    await labsController.CancelBookedLab(labReturnModel);
                                    break;
                                case 7:
                                case 5:
                                    var scanReturnAppointmentModel = (InsertBookScanAppointment)JsonConvert.DeserializeObject<InsertBookScanAppointment>(paymentInitiationLog.TableData);
                                    scanReturnAppointmentModel.TransactionId = transactionId;
                                    scanReturnAppointmentModel.Transaction = transaction;
                                    scanReturnAppointmentModel.SalucroStatusCode = salucroStatusCode;
                                    scanReturnAppointmentModel.SalucroTransactionId = salucroTransactionId;
                                    await bookScanAppointmentController.CancelAsync(scanReturnAppointmentModel);
                                    break;
                                case 6:
                                    var addReceiptModel = (InsertModel)JsonConvert.DeserializeObject<InsertModel>(paymentInitiationLog.TableData);
                                    addReceiptModel.TransactionId = transactionId;
                                    addReceiptModel.Transaction = transaction;
                                    addReceiptModel.SalucroStatusCode = salucroStatusCode;
                                    addReceiptModel.SalucroTransactionId = salucroTransactionId;
                                    await receiptController.AddAsyncHelper(addReceiptModel, (int)addReceiptModel.LocationId);
                                    break;
                            }
                        }
                        else
                        {
                            int modifiedBy = item["custom1"];
                            string reason = item["custom2"];
                            var appointment = await this.appointmentsServices.FindAsync(tId);
                            appointment.Total = amountPaid;
                            //await appointmentServices.CancelAppointmentAsync(appointment, "salucro", transaction, transactionId, salucroStatusCode, salucroTransactionId, modifiedBy, reason);                    
                            await appointmentHelper.CancelAppointmentAsync(appointment, "salucro", transaction, transactionId, salucroStatusCode, salucroTransactionId, modifiedBy, reason);
                        }
                        // Save Request.Form in PaymentResponseLog with true
                        var responseLog = new PaymentResponseLog
                        {
                            JsonData = JsonConvert.SerializeObject(item),
                            IsSuccess = true,
                            CreatedDate = DateTime.Now
                        };
                        await this.unitOfWork.PaymentResponseLog.InsertAsync(responseLog);
                        return this.View();
                    }
                    else
                    {
                        int moduleId = item["custom1"];
                        dynamic paymentInitiationLog = await this.paymentInitiationLogService.FindAsync(tId);

                        // TimeSpan abc = paymentInitiationLog;
                        dynamic data = JsonConvert.DeserializeObject(paymentInitiationLog.TableData);
                        int patientId = data["patientId"] != null ? data["patientId"] : 0; ;
                        var apptId = data["appointmentId"];

                        switch (moduleId)
                        {
                            case 1:
                                var pathsList = new List<String>();
                                if (data["paths"] != null)
                                {
                                    var paths = data["paths"].ToString().Split("$$");
                                    foreach (var path in paths)
                                    {
                                        pathsList.Add(path);
                                    }
                                }
                                var patientModel = (ModifyPatientRequest)JsonConvert.DeserializeObject<ModifyPatientRequest>(paymentInitiationLog.TableData);
                                patientModel.PaymentStatus = salucroStatusCode == 1200;
                                patientModel.TransactionId = transactionId;
                                patientModel.Transaction = transaction;
                                patientModel.SalucroStatusCode = salucroStatusCode;
                                patientModel.SalucroTransactionId = salucroTransactionId;
                                patientModel.PaymentInitiationLogId = (int)item["custom"];
                                patientModel.FilePaths = pathsList;
                                if (patientId != 0)
                                {
                                    await patientsController.UpdateAsync(patientModel);
                                }
                                else
                                {
                                    if (patientModel.IsUnidentified == true)
                                    {
                                        await patientsController.AddUnidentifiedPatient(patientModel);
                                    }
                                    else
                                    {
                                        await patientsController.AddAsync(patientModel);
                                    }
                                }
                                break;
                            case 2:
                                if (apptId != 0 && apptId != null)
                                {
                                    var appointmentModel2 = (AppointmentPayTypeModel)JsonConvert.DeserializeObject<AppointmentPayTypeModel>(paymentInitiationLog.TableData);

                                    //var apptEndTime = string.Empty;
                                    if (appointmentModel2.AppointmentTime == null)
                                    {
                                        var findpt = await this.unitOfWork.Appointments.FindAsync(t => t.AppointmentId == appointmentModel2.AppointmentId);
                                        appointmentModel2.AppointmentTime = findpt.AppointmentTime.ToString();
                                        appointmentModel2.AppointmentEndTime = findpt.AppointmentEndTime.ToString();
                                    }
                                    var type = appointmentModel2.AppointmentTime.GetType();
                                    TimeSpan apt;
                                    TimeSpan apt2;
                                    if (type == typeof(string))
                                    {
                                        var timeSpan = appointmentModel2.AppointmentTime.ToString().Split(":");
                                        apt = TimeSpan.Parse(appointmentModel2.AppointmentTime.ToString());

                                        var endTimeSpan = appointmentModel2.AppointmentTime.ToString().Split(":");
                                        apt2 = TimeSpan.Parse(appointmentModel2.AppointmentEndTime.ToString());
                                        appointmentModel2.AppointmentEndTime = apt2;
                                    }
                                    else
                                    {
                                        var appointmentTime = JsonConvert.DeserializeObject<Time>(appointmentModel2.AppointmentTime.ToString());
                                        var appointmentEndTime = JsonConvert.DeserializeObject<Time>(appointmentModel2.AppointmentEndTime.ToString());
                                        apt2 = TimeSpan.Parse(appointmentEndTime.Hours + ':' + appointmentEndTime.Minutes + ':' + appointmentEndTime.Seconds);
                                        appointmentModel2.AppointmentEndTime = apt2;

                                        apt = TimeSpan.Parse(appointmentTime.Hours + ':' + appointmentTime.Minutes + ':' + appointmentTime.Seconds);

                                    }

                                    //appointmentModel2.AppointmentEndTime = TimeSpan.Parse(appointmentModel2.AppointmentEndTime.ToString());

                                    var appointmentModel = new PatientPaymentModel();
                                    appointmentModel.AppointmentDate = appointmentModel2.AppointmentDate;
                                    appointmentModel.AppointmentId = appointmentModel2.AppointmentId;
                                    appointmentModel.AppointmentNo = appointmentModel2.AppointmentNo;
                                    appointmentModel.AppointmentTimeString = appointmentModel2.AppointmentTimeString;
                                    appointmentModel.PayTypeId = appointmentModel2.PayTypeId;
                                    appointmentModel.PayTypeName = appointmentModel2.PayTypeName;
                                    appointmentModel.Charges = appointmentModel2.Charges;
                                    appointmentModel.ConsultationTypeId = appointmentModel2.ConsultationTypeId;
                                    appointmentModel.CreatedBy = appointmentModel2.CreatedBy;
                                    appointmentModel.CreatedDate = appointmentModel2.CreatedDate;
                                    appointmentModel.DepartmentId = appointmentModel2.DepartmentId;
                                    appointmentModel.DepartmentName = appointmentModel2.DepartmentName;
                                    appointmentModel.EncryptedAppointmentId = appointmentModel2.EncryptedAppointmentId;
                                    appointmentModel.EncryptedPatientId = appointmentModel2.EncryptedPatientId;
                                    appointmentModel.EncryptedProviderId = appointmentModel2.EncryptedProviderId;
                                    appointmentModel.LocationId = appointmentModel2.LocationId;
                                    appointmentModel.LocationName = appointmentModel2.LocationName;
                                    appointmentModel.LogFrom = appointmentModel2.LogFrom;
                                    appointmentModel.PatientAccountId = appointmentModel2.PatientAccountId;
                                    appointmentModel.PatientName = appointmentModel2.PatientName;
                                    appointmentModel.PatientId = appointmentModel2.PatientId;
                                    appointmentModel.PracticeName = appointmentModel2.PracticeName;
                                    appointmentModel.SpecializationId = appointmentModel2.SpecializationId;
                                    appointmentModel.TokenNumber = appointmentModel2.TokenNumber;
                                    appointmentModel.UMRNo = appointmentModel2.UMRNo;
                                    appointmentModel.VisitTypeId = appointmentModel2.VisitTypeId;
                                    appointmentModel.VisitorName = appointmentModel2.VisitorName;
                                    appointmentModel.AppointmentTime = apt;
                                    appointmentModel.ModifiedBy = appointmentModel2.CreatedBy;
                                    appointmentModel.PatientRegistrationAmount = appointmentModel2.Charges != null ? appointmentModel2.Charges : appointmentModel2.PatientRegistrationAmount;
                                    appointmentModel.Total = (decimal)appointmentModel2.TotalAmount;
                                    appointmentModel.PaymentStatus = salucroStatusCode == 1200;
                                    appointmentModel.TransactionId = transactionId;
                                    appointmentModel.Transaction = transaction;
                                    appointmentModel.SalucroStatusCode = salucroStatusCode;
                                    appointmentModel.SalucroTransactionId = salucroTransactionId;
                                    appointmentModel.IsSalucroAppointment = true;
                                    appointmentModel.Amount = appointmentModel2.Amount;
                                    appointmentModel.ProviderId = appointmentModel2.ProviderId;
                                    appointmentModel.ChargeTypesId = appointmentModel2.ChargeTypesId;
                                    appointmentModel.AppointmentEndTime = apt2;
                                    appointmentModel.ProviderAvailabilityId = appointmentModel2.ProviderAvailabilityId;
                                    appointmentModel.DoctorSpecializationChargeModuleDetailsId = appointmentModel2.DoctorSpecializationChargeModuleDetailsId;
                                    appointmentModel.OtherRemarks = appointmentModel2.OtherRemarks;
                                    appointmentModel.AuthorityId = appointmentModel2.AuthorityId;
                                    appointmentModel.ReasonId = appointmentModel2.ReasonId;
                                    appointmentModel.Remarks = appointmentModel2.Remarks;
                                    appointmentModel.Salutation = appointmentModel2.Salutation;
                                    appointmentModel.FirstName = appointmentModel2.FirstName;
                                    appointmentModel.MiddleName = appointmentModel2.MiddleName;
                                    appointmentModel.LastName = appointmentModel2.LastName;
                                    appointmentModel.FullName = appointmentModel2.FullName;
                                    appointmentModel.FatherOrHusband = appointmentModel2.FatherOrHusband;
                                    appointmentModel.DateOfBirth = appointmentModel2.DateOfBirth;
                                    appointmentModel.Age = appointmentModel2.Age;
                                    appointmentModel.Gender = appointmentModel2.Gender;
                                    appointmentModel.MaritalStatus = appointmentModel2.MaritalStatus;
                                    appointmentModel.Email = appointmentModel2.Email;
                                    appointmentModel.Mobile = appointmentModel2.Mobile;
                                    appointmentModel.StreetAddress = appointmentModel2.StreetAddress;
                                    appointmentModel.AddressLine2 = appointmentModel2.AddressLine2;
                                    appointmentModel.City = appointmentModel2.City;
                                    appointmentModel.State = appointmentModel2.State;
                                    appointmentModel.Zipcode = appointmentModel2.Zipcode;
                                    appointmentModel.CountryId = appointmentModel2.CountryId;
                                    appointmentModel.ModifiedBy = appointmentModel2.ModifiedBy;
                                    appointmentModel.ModifiedDate = DateTime.UtcNow;
                                    appointmentModel.AadharNo = appointmentModel2.AadharNo;
                                    appointmentModel.PatientReferredById = appointmentModel2.PatientReferredById;
                                    appointmentModel.ReferredByName = appointmentModel2.ReferredByName;
                                    appointmentModel.HWCPatientId = appointmentModel2.HWCPatientId;
                                    appointmentModel.Education = appointmentModel2.Education;
                                    appointmentModel.Occupation = appointmentModel2.Occupation;
                                    appointmentModel.Nationality = appointmentModel2.Nationality;
                                    appointmentModel.Religion = appointmentModel2.Religion;
                                    appointmentModel.IdProofId = appointmentModel2.IdProofId;
                                    appointmentModel.IdProofValue = appointmentModel2.IdProofValue;
                                    appointmentModel.HowDidYouKnowId = appointmentModel2.HowDidYouKnowId;
                                    appointmentModel.EducationId = appointmentModel2.EducationId;
                                    appointmentModel.OccupationId = appointmentModel2.OccupationId;
                                    //appointmentModel.BirthMark1 = appointmentModel2.BirthMark1;
                                    //appointmentModel.BirthMark2 = appointmentModel2.BirthMark2;
                                    //appointmentModel.RelationType = appointmentModel2.RelationType;
                                    appointmentModel.OccupationDetail = appointmentModel2.OccupationDetail;
                                    appointmentModel.InsuranceCompanyId = appointmentModel2.InsuranceCompanyId;
                                    appointmentModel.RelativeDetails = appointmentModel2.RelativeDetails;
                                    appointmentModel.Insurances = appointmentModel2.Insurances;
                                    appointmentModel.EmergencyContacts = appointmentModel2.EmergencyContacts;
                                    appointmentModel.AppointmentTotal = appointmentModel2.AppointmentTotal;
                                    appointmentModel.PatientTotal = appointmentModel2.PatientTotal;

                                    await appointmentsController.UpdatePaymentHelper(appointmentModel);
                                }

                                else if (patientId != 0)
                                {
                                    var appointmentModel = (BookAppointmentRequest)JsonConvert.DeserializeObject<BookAppointmentRequest>(paymentInitiationLog.TableData);
                                    appointmentModel.PatientRegistrationAmount = appointmentModel.Charges != null ? appointmentModel.Charges : appointmentModel.PatientRegistrationAmount;
                                    var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == appointmentModel.PatientId);
                                    appointmentModel.TotalAmount = patient.PaymentStatus == true ? amountPaid : appointmentModel.TotalAmount;
                                    appointmentModel.Total = patient.PaymentStatus == true ? (decimal)appointmentModel.TotalAmount : appointmentModel.AfterDiscount;
                                    appointmentModel.PaymentStatus = salucroStatusCode == 1200 ? true : false;
                                    appointmentModel.TransactionId = transactionId;
                                    appointmentModel.Transaction = transaction;
                                    appointmentModel.SalucroStatusCode = salucroStatusCode;
                                    appointmentModel.SalucroTransactionId = salucroTransactionId;
                                    appointmentModel.IsSalucroAppointment = true;
                                    await appointmentsController.AddAsyncHelper(appointmentModel);
                                }
                                else
                                {
                                    var filePaths = new List<String>();
                                    if (data["paths"] != null)
                                    {
                                        var paths = data["paths"].ToString().Split("$$");
                                        foreach (var path in paths)
                                        {
                                            filePaths.Add(path);
                                        }
                                    }
                                    var patApptModel = (QuickScheduleRequest)JsonConvert.DeserializeObject<QuickScheduleRequest>(paymentInitiationLog.TableData);
                                    patApptModel.TotalAmount = (decimal)patApptModel.TotalAmount;
                                    patApptModel.PaymentStatus = salucroStatusCode == 1200 ? true : false;
                                    patApptModel.TransactionId = transactionId;
                                    patApptModel.Transaction = transaction;
                                    patApptModel.SalucroStatusCode = salucroStatusCode;
                                    patApptModel.SalucroTransactionId = salucroTransactionId;
                                    patApptModel.IsSalucroAppointment = true;
                                    patApptModel.FilePaths = filePaths;
                                    await appointmentsController.AddAppointmentAsync(patApptModel);
                                }
                                break;

                            case 3:
                                var pharmacyModel = (NewSalesBill)JsonConvert.DeserializeObject<NewSalesBill>(paymentInitiationLog.TableData);
                                pharmacyModel.TotalAmount = amountPaid;
                                pharmacyModel.PaymentStatus = salucroStatusCode == 1200 ? true : false;
                                pharmacyModel.TransactionId = transactionId;
                                pharmacyModel.Transaction = transaction;
                                pharmacyModel.SalucroStatusCode = salucroStatusCode;
                                pharmacyModel.SalucroTransactionId = salucroTransactionId;
                                pharmacyModel.PaymentInitiationLogId = (int)item["custom"];
                                pharmacyModel.IsSalucroBill = true;
                                await pharmacyController.AddAsyncHelper(pharmacyModel, (int)pharmacyModel.LocationId);
                                break;
                            case 4:
                                var labModel = (LabBookingModel)JsonConvert.DeserializeObject<LabBookingModel>(paymentInitiationLog.TableData);
                                labModel.TotalAmount = amountPaid;
                                labModel.PaymentStatus = salucroStatusCode == 1200 ? true : false;
                                labModel.TransactionId = transactionId;
                                labModel.Transaction = transaction;
                                labModel.SalucroStatusCode = salucroStatusCode;
                                labModel.SalucroTransactionId = salucroTransactionId;
                                labModel.PaymentInitiationLogId = (int)item["custom"];
                                labModel.IsSalucroBill = true;
                                var result = await labTransactionController.AddLabBillAsync(labModel);
                                break;

                            case 7:
                            case 5:
                                var bookScanAppointmentModel = (InsertBookScanAppointment)JsonConvert.DeserializeObject<InsertBookScanAppointment>(paymentInitiationLog.TableData);
                                if (bookScanAppointmentModel.PatientId != 0)
                                {
                                    var patient = await this.unitOfWork.Patients.FindAsync(m => m.PatientId == bookScanAppointmentModel.PatientId);
                                    if (patient.PaymentStatus == true)
                                    {
                                        bookScanAppointmentModel.TotalAmount = amountPaid;
                                    }
                                }
                                bookScanAppointmentModel.PaymentStatus = salucroStatusCode == 1200;
                                bookScanAppointmentModel.TransactionId = transactionId;
                                bookScanAppointmentModel.Transaction = transaction;
                                bookScanAppointmentModel.SalucroStatusCode = salucroStatusCode;
                                bookScanAppointmentModel.SalucroTransactionId = salucroTransactionId;
                                bookScanAppointmentModel.IsSalucroAppointment = true;
                                if (bookScanAppointmentModel.Category != null)
                                {
                                    if (bookScanAppointmentModel.Category == "ScanNotification")
                                    {
                                        await bookScanAppointmentController.UpdatePatientDetailsPaymentAsync(bookScanAppointmentModel);
                                    }
                                }
                                else
                                {
                                    await bookScanAppointmentController.AddAsync(bookScanAppointmentModel);
                                }
                                break;

                            case 6:
                                var addReceiptModel = (InsertModel)JsonConvert.DeserializeObject<InsertModel>(paymentInitiationLog.TableData);
                                addReceiptModel.TransactionId = transactionId;
                                addReceiptModel.Transaction = transaction;
                                addReceiptModel.SalucroStatusCode = salucroStatusCode;
                                addReceiptModel.SalucroTransactionId = salucroTransactionId;
                                addReceiptModel.IsSalucroAdmissionReceipt = true;
                                await receiptController.AddAsyncHelper(addReceiptModel, (int)addReceiptModel.LocationId);
                                break;
                        }
                        // Save Request.Form in PaymentResponseLog with true
                        var responseLog = new PaymentResponseLog
                        {
                            JsonData = JsonConvert.SerializeObject(item),
                            IsSuccess = true,
                            CreatedDate = DateTime.Now
                        };
                        await this.unitOfWork.PaymentResponseLog.InsertAsync(responseLog);
                        return this.View();
                    }
                }
                catch (Exception ex)
                {
                    // Save Request.Form in PaymentResponseLog with true
                    var responseLog = new PaymentResponseLog
                    {
                        JsonData = JsonConvert.SerializeObject(item),
                        IsSuccess = false,
                        Exception = ex.Message,
                        CreatedDate = DateTime.Now
                    };
                    await this.unitOfWork.PaymentResponseLog.InsertAsync(responseLog);
                    return this.View();
                }
            }
            else
            {
                return this.View();
            }
        }

        #region Private Functions

        /// <summary>
        /// The to JSON.
        /// </summary>
        /// <param name="collection">
        /// The collection.
        /// </param>
        /// <returns>
        /// The <see cref="string"/>.
        /// </returns>
        private static string ToJson(IFormCollection collection)
        {
            var list = collection.Keys.ToDictionary<string, string, string>(key => key, key => collection[key]);
            return JsonConvert.SerializeObject(list);
        }

        #endregion
    }
}