namespace Hims.Api.Controllers
{
    using System.Threading.Tasks;

    using Domain.Services;
    using Domain.Configurations;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;

    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.UserModels.Laboratory;
    using Shared.UserModels.Labs;
    using System.Collections.Generic;

    using Utilities;
    using Hims.Shared.Library.Enums;
    using System;
    using System.Linq;
    using Hims.Domain.Helpers;
    using Hims.Shared.UserModels.Common;
    using Hims.Shared.UserModels.ServiceOrder;
    using Senders;
    using Hims.Api.Models;
    using System.IO;
    using Newtonsoft.Json;

    /// <inheritdoc />
    [Authorize]
    [Route("api/lab-transaction")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class LabTransactionController : BaseController
    {
        /// <summary>
        /// The lab transaction service.
        /// </summary>
        private readonly ILabTransactionService labTransactionService;

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

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

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

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

        /// <summary>
        /// The resource service
        /// </summary>
        private readonly IResourceService resourceService;

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

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

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

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

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

        /// <summary>
        /// The setting service
        /// </summary>
        private readonly ISettingService settingService;

        /// <inheritdoc />
        public LabTransactionController(ILabLogService labLogService, ILabTransactionService labTransactionService, IWebNotificationService webNotificationService, IAESHelper aesHelper, IWhatsAppSMSSender whatsAppSMSSender, IResourceService resourceService, IFtpUploadHelper ftpUploadHelper, IRunningEnvironment runningEnvironment, IPatientService patientService, IPushNotificationHelper pushNotificationHelper, IAccountSessionService accountSessionServices, ISettingService settingService)
        {
            this.labLogService = labLogService;
            this.labTransactionService = labTransactionService;
            this.webNotificationService = webNotificationService;
            this.aesHelper = aesHelper;
            this.whatsAppSMSSender = whatsAppSMSSender;
            this.resourceService = resourceService;
            this.ftpUploadHelper = ftpUploadHelper;
            this.runningEnvironment = runningEnvironment;
            this.patientService = patientService;
            this.pushNotificationHelper = pushNotificationHelper;
            this.accountSessionServices = accountSessionServices;
            this.settingService = settingService;
        }

        /// <summary>
        /// Adds the lab bill asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-booking")]
        [Consumes("multipart/form-data")]
        public async Task<ActionResult> AddLabBillAsync([FromForm] LabBookingModel model/*, [FromHeader] LocationHeader? location*/)
        {
            model = (LabBookingModel)EmptyFilter.Handler(model);
            model.Labs = model.Labs.Count > 0 ? model.Labs : JsonConvert.DeserializeObject<List<NewLabBookingDetailModel>>(model.LabList);
            if (model.PatientId == 0)
            {
                var patientId = await this.AddPatientsAsync(model);
                if (patientId == -1)
                {
                    return this.Conflict("Given mobile number has already been exists with us.");
                }
                model.PatientId = patientId;
            }
            //model.LocationId = Convert.ToInt32(location.LocationId);
            if (model.Labs.Count == 0)
            {
                string message1 =  "Unable to Add labs to bill.";
                return this.BadRequest(message1);
            }

            var response = await this.labTransactionService.AddLabBillAsync(model, new List<InsertLabServiceHelperModel>());
            if (response>0)
            {
                var accountSessionPatientModel = await this.accountSessionServices.FetchDeviceTokenAsync((int)model.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 (model.PatientId != null)
                    {
                        string TestName = "";
                        var Labs = model.Labs.ToList();
                        string NotificationText = "";
                        for (int i = 0; i < Labs.Count; i++)
                        {
                            TestName = TestName + Labs[i].TestName;
                            if (i != Labs.Count - 1)
                            {
                                TestName = TestName + ", ";
                            }
                        }
                        if (model.Labs.Count() > 1)
                        {
                            NotificationText = $@"Booking Success for lab test(s) " + TestName.ToUpper() + "";
                        }
                        else
                        {
                            NotificationText = $@"Booking Success for lab test(s) " + TestName.ToUpper() + "";
                        }
                        //NotificationText = $@"Your " + TestName.ToUpper() + " Tests are Booked Succesfully.";
                        //if (model.index != null)
                        //{
                        //    NotificationText = $@"Your " + model.Labs[(int)model.index].TestName.ToUpper() + " Test is Cancelled Succesfully.";

                        //}
                        //else
                        //{

                        //}
                        //"Your Lab Tests  is Booked Succesfully."
                        if (deviceTokenForProviderAndroid.Any())
                        {
                            await this.pushNotificationHelper.SendAltAsync(
                                "Hims",
                                NotificationText,
                                "LabBooked",
                                deviceTokenForProviderAndroid,
                                new List<string>(),
                                model.RequisitionNumber,
                                DateTime.Now.ToString(),
                                null);
                        }

                        if (deviceTokenForProviderIOS.Any())
                        {
                            await this.pushNotificationHelper.SendAltAsync(
                                "Hims",
                                NotificationText,
                                "LabBooked",
                                new List<string>(),
                                deviceTokenForProviderIOS,
                                model.RequisitionNumber,
                                DateTime.Now.ToString(),
                                null);
                        }
                    }
                }
            }

            // commented because of performance issue.
            var WhatsAppMessageSetting = await this.settingService.FetchAsync("WhatsAppMsgService",null,null);
            var WhatsAppMessage = WhatsAppMessageSetting.ToList();
            var PrecautionMesage = "";
            if (response > 0 && (bool)WhatsAppMessage[0].Active)
            {
                var patientdetails = await this.resourceService.FetchPatientDetails((int)model.PatientId);
                string LabName = "";
                foreach (var lab in model.Labs)
                {
                    if (!(string.IsNullOrEmpty(lab.TestPrecaution)))
                    {
                        PrecautionMesage += $@"*{lab.TestName} Precaution:*- -{ lab.TestPrecaution}.- -";

                    }
                    LabName += lab.TestName;
                    LabName += ", ";
                }
                LabName = LabName.Remove(LabName.Length - 2);
                bool ret = await this.whatsAppSMSSender.SendLabBookingWhatsAppMessage(patientdetails.Mobile, patientdetails.FullName, LabName);
                if (!(string.IsNullOrEmpty(PrecautionMesage)))
                {
                    bool PrecationsWhatsAppMessageReponse = await this.whatsAppSMSSender.SendLabPrecautionWhatsAppMessage(patientdetails.Mobile, patientdetails.FullName, PrecautionMesage);
                }
            }
            var message = string.Empty;

            if (response > 0)
            {
                var labLogModel = new LabLogModel
                {
                    AccountId = model.CreatedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_BookingLab,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has added <b>Lab Bill</b> for <strong>{model.PatientName}</strong> successfully.",
                    LocationId = Convert.ToInt32(model.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            switch (response)
            {
                case -1:
                    message = "Unable to add bill.";
                    break;
                case -2:
                case -3:
                    message = "Unable to add labs to bill.";
                    break;
                case -4:
                    message = "Unable to add billing details.";
                    break;
            }

            if (model.AppointmentId != null && model.AppointmentId > 0)
            {

                await this.webNotificationService.UpdateReadStatus((int)model.AppointmentId, (int)ModulesMasterType.Lab);
            }

            return !string.IsNullOrEmpty(message) ? this.BadRequest(message) : this.Success(response);
        }

        /// <summary>
        /// Fetches the added lab bill asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-added-lab-bill")]
        public async Task<ActionResult> FetchAddedLabBillAsync([FromBody] LabBookingModel model)
        {
            model = (LabBookingModel)EmptyFilter.Handler(model);
            var responses = await this.labTransactionService.FetchAddedLabBillAsync(model);
            foreach (var resource in responses)
            {
                resource.EncryptedId = this.aesHelper.Encode(resource.PatientId.ToString());
            }
            return this.Success(responses);
        }

        /// <summary>
        /// Fetches the labs for sample collection and Home Sample Mobile asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="header">The header.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-lab-for-sample-collection")]
        public async Task<ActionResult> FetchLabsForSampleCollectionAsync([FromBody] LabSampleHandlerModel model, [FromHeader] LocationHeader header)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(header.LocationId);
            var response = await this.labTransactionService.FetchLabsForSampleCollectionAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Collects the lab samples and generate barcode.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("collect-sample")]
        public async Task<ActionResult> CollectLabSamplesAndGenerateBarcode([FromBody] LabSampleHandlerModel model, [FromHeader] LocationHeader location)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            int locationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.CollectSampleAndGenerateBarcodeAsync(model, locationId);
            if (response > 0)
            {
                var labLogModel = new LabLogModel
                {
                    AccountId = model.CreatedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Sample_Collection,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has Collected <b>Lab Samples</b> of <strong>{model.RequisitionNumber}</strong> successfully.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            var message = string.Empty;
            switch (response)
            {
                case 0:
                    message = "Sample receive status not found";
                    break;
                case -1:
                    message = "Unable to receive and generate barcode";
                    break;
                case -2:
                    message = "Lab bill not exists";
                    break;
                case -3:
                    message = "Sample already collected for this lab";
                    break;
            }

            return string.IsNullOrEmpty(message) ? this.Success(response) : this.BadRequest(message);
        }

        /// <summary>
        /// Transfers the collected samples asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("transfer-samples")]
        public async Task<ActionResult> TransferCollectedSamplesAsync([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.TransferCollectedSampleAsync(model);
            if (response > 0)
            {
                string temp = "";
                if (model.TransferredTemperature != null)
                {
                    temp = $@"with {model.TransferredTemperature}°C";
                }
                var header = await this.labTransactionService.FetchTransferHeader(response);
                var location1 = await this.resourceService.FetchLocationsAsync();
                var transferedlocation = location1.First(l => l.Id == model.TransferedLocationId);
                var labLogModel = new LabLogModel
                {
                    AccountId = model.TransferedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Sample_Transfer,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has <b>Tranfered </b> Lab Samples to {transferedlocation.Value} with Tranfer No as <strong>{header.TransferNumber}</strong> successfully{temp}.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            var message = string.Empty;
            switch (response)
            {
                case -1:
                    message = "Transfer status not found.";
                    break;
                case -2:
                    message = "Not able to create transfer user details.";
                    break;
                case -3:
                    message = "Unable to add selected labs in transfer.";
                    break;
                case -4:
                    message = "Unable to update transfer status";
                    break;
            }

            return string.IsNullOrEmpty(message) ? this.Success(response) : this.BadRequest(message);
        }

        /// <summary>
        /// Fetches the transfered labs asynchronous.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="location"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-transfered-samples")]
        public async Task<ActionResult> FetchTransferedLabsAsync([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model ??= new LabTransferModel();
            model.CreatedLabLocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.FetchTransferedLabsAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the labs for sample receiving asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-samples-to-receive")]
        public async Task<ActionResult> FetchLabsForSampleReceivingAsync([FromBody] LabReceiveModel model, [FromHeader] LocationHeader location)
        {
            model ??= new LabReceiveModel();
            model.TransferedLocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.FetchLabReceiveSampleAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Called when receive sample asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("on-sample-receive")]
        public async Task<ActionResult> OnReceiveSampleAsync([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.OnReceiveSampleAsync(model);
            if (response > 0)
            {
                string temp = "";
                if (model.ReceivedTemperature != null)
                {
                    temp = $@"with {model.ReceivedTemperature}°C";
                }
                var header = await this.labTransactionService.FetchTransferHeader(model.LabTransferHeaderId);
                var labLogModel = new LabLogModel
                {
                    AccountId = model.ReceivedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Sample_Receive,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has <b>Received </b> Lab Samples of  <strong>{header.TransferNumber}</strong> successfully{temp}.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the sample received labs asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>

        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-received-labs")]
        public async Task<ActionResult> FetchSampleReceivedLabsAsync([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            model.TransferedLocationId = Convert.ToInt32(location.LocationId);
            var responses = await this.labTransactionService.FetchTransferedLabsAsync(model);
            foreach (var resource in responses)
            {
                resource.EncryptedId = this.aesHelper.Encode(resource.PatientId.ToString());
            }
            return this.Success(responses);
        }

        /// <summary>
        /// Fetches the labs parameter for input asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("lab-parameter-for-input")]
        public async Task<ActionResult> FetchLabsParameterForInputAsync([FromBody] LabTransferModel model)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.FetchParametersRequiredForInputAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the lab parameter asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-lab-parameter-input")]
        public async Task<ActionResult> AddLabParameterAsync([FromBody] InputObservedValueModel model)
        {
            model = (InputObservedValueModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.AddParametersToLabs(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the lab template asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-lab-template-input")]
        public async Task<ActionResult> AddLabTemplateAsync([FromBody] TemplateInputModel model)
        {
            model = (TemplateInputModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.AddTemplateDetailsToLabs(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the booked lab status asynchronous.
        /// </summary>
        /// <param name="newLabBookingHeaderId">The new lab booking header identifier.</param>
        /// <param name="newLabBookingDetailId">The new lab booking detail identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-lab-status-timeline")]
        public async Task<ActionResult> FetchBookedLabStatusAsync(int? newLabBookingHeaderId, int? newLabBookingDetailId)
        {
            if (newLabBookingDetailId == null && newLabBookingHeaderId == null)
            {
                return this.BadRequest("parameters are not valid");
            }

            var response = await this.labTransactionService.FetchLabStatusTimeline(newLabBookingHeaderId, newLabBookingDetailId);
            return this.Success(response);
        }

        /// <summary>
        /// Collects the lab samples and generate barcode new.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("collect-sample-new")]
        public async Task<ActionResult> CollectLabSamplesAndGenerateBarcodeNew([FromBody] List<LabSampleHandlerModel> model, [FromHeader] LocationHeader location)
        {
            model = (List<LabSampleHandlerModel>)EmptyFilter.Handler(model);
            int locationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.CollectSampleAndGenerateBarcodeAsyncNew(model, locationId);
            if (response > 0)
            {
                for (int i = 0; i < model.Count; i++)
                {
                    var labLogModel = new LabLogModel
                    {
                        AccountId = model[i].CreatedBy,
                        LabLogTypeId = (int)LabLogTypes.Lab_Sample_Collection,
                        LogFrom = (short)model[i].RoleId,
                        LogDate = DateTime.Now,
                        LogDescription = $"{model[i].CreatedByName} has Collected <b>Lab Sample</b> in <strong>{model[i].RequisitionNumber}</strong> successfully.",
                        LocationId = Convert.ToInt32(location.LocationId)
                    };
                    await this.labLogService.LogAsync(labLogModel);
                }

            }
            var message = string.Empty;
            switch (response)
            {
                case 0:
                    message = "Sample receive status not found";
                    break;
                case -1:
                    message = "Unable to receive and generate barcode";
                    break;
                case -2:
                    message = "Lab bill not exists";
                    break;
                case -3:
                    message = "Sample already collected for this lab";
                    break;
            }

            return string.IsNullOrEmpty(message) ? this.Success(response) : this.BadRequest(message);
        }

        /// <summary>
        /// Fetches the transfered labs asynchronous.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="location"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-transfered-track-record")]
        public async Task<ActionResult> FetchTransferedTrackRecord([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model ??= new LabTransferModel();
            model.CreatedLabLocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.FetchTransferedTrackRecords(model);
            return this.Success(response);

        }

        /// <summary>
        /// Fetches the patient lab bill asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-patient-lab-bill")]
        public async Task<ActionResult> FetchPatientLabBillAsync([FromBody] PatientLabBillModel model)
        {
            model = (PatientLabBillModel)EmptyFilter.Handler(model);
            var responses = await this.labTransactionService.FetchPatientLabBillAsync(model);
            return this.Success(responses);
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-demograph-data")]
        public async Task<ActionResult> FetchDemographDataAsync([FromBody] LabTransferModel model)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            var responses = await this.labTransactionService.FetchTransferedLabsAsync(model);
            foreach (var resource in responses)
            {
                resource.EncryptedId = this.aesHelper.Encode(resource.PatientId.ToString());
            }
            return this.Success(responses);
        }


        /// <summary>
        /// Uploads the lab reports asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-lab-report")]
        [Consumes("multipart/form-data")]
        public async Task<ActionResult> UploadLabReportsAsync([FromForm] NewLabBookingDetailModel model,[FromHeader] LocationHeader location)
        {
            model = (NewLabBookingDetailModel)EmptyFilter.Handler(model);

            var files = this.Request.Form.Files;

            int response = 0;

            if (files[0] != null)
            {
                #region Manish Code FTP
                var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/LabReports/{model.NewLabBookingDetailId}";

                try
                {
                    await this.ftpUploadHelper.CreateDirectory(filePath);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                var dbPath = $@"{model.TestCode}_{DateTime.UtcNow.Ticks}{Path.GetExtension(files[0].FileName)}";
                filePath += $@"/{dbPath}";


                var uploadResponse = await this.ftpUploadHelper.UploadFromFileAsync(filePath, files[0]);

                if (uploadResponse <= 0)
                {
                    return this.BadRequest();
                }

                #endregion

                model.ReportUrl = $@"LabReports/{model.NewLabBookingDetailId}/{dbPath}";

                response = await this.labTransactionService.UploadLabReportAsync(model);
            }
            if (response>0)
            {
                var labLogModel = new LabLogModel
                {
                    AccountId = model.UploadedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Document_Upload,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has  Verified <b>Lab Test</b> of <strong>{model.RequisitionNumber} - {model.TestName}</strong>.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            return response > 0 ? this.Success("Report uploaded successfully") : this.BadRequest("Unable to upload file.");
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-lab-booking-detail")]
        public async Task<ActionResult> FetchNewLabBookingDetailAsync([FromBody] NewLabBookingDetailModel model)
        {
            model = (NewLabBookingDetailModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.FetchNewLabBookingDetailAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the labs for sample transfer asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="header">The header.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-lab-for-sample-transfer")]
        public async Task<ActionResult> FetchLabsForSampleTransferAsync([FromBody] LabSampleHandlerModel model, [FromHeader] LocationHeader header)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(header.LocationId);
            var response = await this.labTransactionService.FetchLabsForSampleTransferAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the new lab booking dedtail asynchronous.
        /// </summary>
        /// <param name="newLabBookingDetailId">The new lab booking detail identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-new-lab-booking-detail")]
        public async Task<ActionResult> FetchNewLabBookingDedtailAsync(int newLabBookingDetailId)
        {
            var response = await this.labTransactionService.FetchNewLabBookingDetail(newLabBookingDetailId);
            return this.Success(response);
        }

        /// <summary>
        /// Called when [verify lab by technician asynchronous].
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-technician-verification")]
        public async Task<ActionResult> OnVerifyLabByTechnicianAsync([FromBody] LabTechnicianVerificationModel model,[FromHeader]LocationHeader location)
        {
            model = (LabTechnicianVerificationModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.AddTechnicianVerificationAsync(model);
            if (response > 0)
            {
                var labLogModel = new LabLogModel
                {
                    AccountId = model.TechnicianId,
                    LabLogTypeId = (int)LabLogTypes.Lab_Technician_Verified,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has  Verified <b>Lab Test</b> of <strong>{model.RequisitionNumber} - {model.TestName}</strong>.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            return this.Success(response);
        }

        [AllowAnonymous]
        [HttpPost]
        [Route("fetch-for-technician-and-doctor")]
        public async Task<ActionResult> FetchForTechnicianAndDoctorAsync([FromBody] LabSampleHandlerModel model, [FromHeader] LocationHeader location)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.FetchLabsForTechnicianAndDoctorAsync(model);
            var responseList = new List<LabTransferModel>();
            if (response.Count() > 0)
            {
                responseList = response.ToList();
                foreach (var record in responseList)
                {
                    if (record.AppointmentId != null)
                    {
                        record.EncryptedAppointmentId = this.aesHelper.Encode(record.AppointmentId.ToString());
                    }
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the previous transfer detail asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-previous-transfer-detail")]
        public async Task<ActionResult> FetchPreviousTransferDetailAsync([FromBody] CheckTransferLocationModel model)
        {
            model = (CheckTransferLocationModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.FetchPreviousTransferDetailsAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Uploads the test consenyt form asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-lab-consent-form")]
        [Consumes("multipart/form-data")]
        public async Task<ActionResult> UploadTestConsenytFormAsync([FromForm] LabSampleHandlerModel model, [FromHeader] LocationHeader location)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            int locationId = Convert.ToInt32(location.LocationId);
            var files = this.Request.Form.Files;

            int response = 0;

            if (files[0] != null)
            {
                #region Manish Code FTP
                var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/LabConsentForm/{model.NewLabBookingDetailId}";

                try
                {
                    await this.ftpUploadHelper.CreateDirectory(filePath);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                var dbPath = $@"{model.TestCode}_{DateTime.UtcNow.Ticks}{Path.GetExtension(files[0].FileName)}";
                filePath += $@"/{dbPath}";


                var uploadResponse = await this.ftpUploadHelper.UploadFromFileAsync(filePath, files[0]);

                if (uploadResponse <= 0)
                {
                    return this.BadRequest();
                }

                #endregion

                model.ConsentFormUrl = $@"LabConsentForm/{model.NewLabBookingDetailId}/{dbPath}";

                response = await this.labTransactionService.UploadLabConsentFormAsync(model,locationId);

            }
            return response > 0 ? this.Success("Consent Form uploaded successfully") : this.BadRequest("Unable to upload file.");
        }

        /// <summary>
        /// Fetches the labs without cancelled asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-labs-without-cancelled")]
        public async Task<ActionResult> FetchLabsWithoutCancelledAsync([FromBody] LabSampleHandlerModel model)
        {
            model = (LabSampleHandlerModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.FetchLabsWithoutCancelledAsync(model);
            return this.Success(response);
        }


        [HttpPost]
        [Route("on-sample-receive-new")]
        public async Task<ActionResult> OnReceiveSampleNewAsync([FromBody] SampleReceiveNewUserModel model, [FromHeader] LocationHeader location)
        {
            model = (SampleReceiveNewUserModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.OnReceiveSampleNewAsync(model);
            if (response > 0)
            {
                var header = await this.labTransactionService.FetchTransferHeader(model.Labs[0].LabTransferHeaderId);
                var labLogModel = new LabLogModel
                {
                    AccountId = model.ReceivedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Sample_Receive,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has <b>Received </b> {model.Labs.Count} Samples of  <strong>{header.TransferNumber}</strong> successfully.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            return this.Success(response);
        }

        [HttpPost]
        [Route("department-accept-sample")]
        public async Task<ActionResult> SampleDepartmentAcceptAsync([FromBody] LabTransferModel model, [FromHeader] LocationHeader location)
        {
            model = (LabTransferModel)EmptyFilter.Handler(model);
            var response = await this.labTransactionService.onDepartmentAcceptAsync(model);
            if (response > 0)
            {
                var header = await this.labTransactionService.FetchTransferHeader(model.LabTransferHeaderId);
                var labLogModel = new LabLogModel
                {
                    AccountId = model.ReceivedBy,
                    LabLogTypeId = (int)LabLogTypes.Lab_Department_Accept,
                    LogFrom = (short)model.RoleId,
                    LogDate = DateTime.Now,
                    LogDescription = $"{model.CreatedByName} has <b>Received </b> Department Samples of  <strong>{model.RequisitionNumber} - {model.TestName}</strong> successfully.",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.labLogService.LogAsync(labLogModel);
            }
            return this.Success(response);
        }

        /// <summary>
        /// Adds the patients asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        private async Task<int> AddPatientsAsync(LabBookingModel model)
        {
            var singlePatient = new PatientModel();
            singlePatient.FirstName = model.PatientName;
            singlePatient.FullName = model.PatientName;
            singlePatient.Gender = model.Gender;
            singlePatient.Age = Convert.ToInt16(model.Age);
            singlePatient.Mobile = model.Mobile;
            singlePatient.CreatedBy = model.CreatedBy;
            singlePatient.LocationId = (int)model.LocationId;
            singlePatient.CountryId = 1;
            singlePatient.PaymentStatus = false;
            singlePatient.IsNewPatient = true;
            singlePatient.TempPatient = true;
            singlePatient.UMRNo = model.Mobile;

            List<PatientFamilyModel> singlePatientFamily = new List<PatientFamilyModel>();
            List<PatientEmergencyModel> singleEmergencyPatientInfo = new List<PatientEmergencyModel> { new PatientEmergencyModel { FullName = "", Relation = "", Mobile = "" } };
            try
            {
                var (accountId, patientId, guid) = await this.patientService.AddAsync(singlePatient, singleEmergencyPatientInfo, new List<PatientInsuranceModel>(), new PatientFamilyModel(), singlePatientFamily ?? new List<PatientFamilyModel>());
                return patientId;
            }
            catch (Exception ex)
            {
                return -1;
            }
        }

        /// <summary>
        /// Transfers the collected external samples asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("transfer-samples-external")]
        public async Task<ActionResult> TransferCollectedExternalSamplesAsync([FromBody] ExternalLabTransferUserModel model, [FromHeader] LocationHeader location)
        {
            model = (ExternalLabTransferUserModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.TransferCollectedExternalSampleAsync(model);
            var message = string.Empty;
            switch (response)
            {
                case -1:
                    message = "Transfer status not found.";
                    break;
                case -2:
                    message = "Transfer details not found.";
                    break;
                case -3:
                    message = "Unable to add selected labs in transfer.";
                    break;
                case -4:
                    message = "Unable to update sample transfer status";
                    break;
                case -5:
                    message = "Unable to update Detail transfer status";
                    break;
            }

            return string.IsNullOrEmpty(message) ? this.Success(response) : this.BadRequest(message);
        }

        [HttpPost]
        [Route("fetch-transfered-samples-external")]
        public async Task<ActionResult> FetchExternalTransferedLabsAsync([FromBody] FetchExternalLabTransferUserModel model, [FromHeader] LocationHeader location)
        {
            model ??= new FetchExternalLabTransferUserModel();
            model.FromLocationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.FetchExternalTransferedLabsAsync(model);
            return this.Success(response);
        }

        //For Home Sample Collection insert
        /// <summary>
        /// For Home Sample Collection insert
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("home-collect-sample")]
        public async Task<ActionResult> HomeSampleCollection([FromBody] HomeSampleCollectionInsertModel model, [FromHeader] LocationHeader location)
        {
            model = (HomeSampleCollectionInsertModel)EmptyFilter.Handler(model);
            var Sample = new List<LabSampleHandlerModel>();
            Sample = new List<LabSampleHandlerModel> { new LabSampleHandlerModel { NewLabBookingDetailId = model.NewLabBookingDetailId,NewLabBookingHeaderId = model.NewLabBookingHeaderId,CreatedBy = model.CreatedBy,LabMainDetailId = model.LabMainDetailId,LabSampleCollectionId = model.LabSampleCollectionId,LabSampleCollectionDetailId = model.LabSampleCollectionDetailId,CreatedByName = model.CreatedByName,RequisitionNumber = model.RequisitionNumber } };
            int locationId = Convert.ToInt32(location.LocationId);
            var response = await this.labTransactionService.CollectSampleAndGenerateBarcodeAsyncNew(Sample, locationId);
            if (response > 0)
            {
                for (int i = 0; i < Sample.Count; i++)
                {
                    var labLogModel = new LabLogModel
                    {
                        AccountId = Sample[i].CreatedBy,
                        LabLogTypeId = (int)LabLogTypes.Lab_Sample_Collection,
                        LogFrom = (short)Sample[i].RoleId,
                        LogDate = DateTime.Now,
                        LogDescription = $"Raider{Sample[i].CreatedByName} has Collected <b>Home Lab Sample</b> in <strong>{Sample[i].RequisitionNumber}</strong> successfully.",
                        LocationId = Convert.ToInt32(location.LocationId)
                    };
                    await this.labLogService.LogAsync(labLogModel);
                }

            }
            var message = string.Empty;
            switch (response)
            {
                case 0:
                    message = "Sample receive status not found";
                    break;
                case -1:
                    message = "Unable to receive and generate barcode";
                    break;
                case -2:
                    message = "Lab bill not exists";
                    break;
                case -3:
                    message = "Sample already collected for this lab";
                    break;
            }

            return string.IsNullOrEmpty(message) ? this.Success(response) : this.BadRequest(message);
        }
    }

}