
namespace Hims.Api.Controllers
{
    using Domain.Configurations;
    using Domain.Helpers;
    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Entities;
    using Hims.Domain.Repositories.UnitOfWork;
    using Hims.Shared.EntityModels;
    using Hims.Shared.Library;
    using Hims.Shared.UserModels.Filters;
    using Hims.Shared.UserModels.OBEncounter;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Shared.DataFilters;
    using Shared.Library.Enums;
    using Shared.UserModels;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Utilities;
    using ob = Shared.UserModels.OBEncounter;


    /// <summary>
    /// The internal medicine controller.
    /// </summary>
    [Route("api/ob-encounter")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class OBEncounterController : BaseController
    {
        /// <summary>
        /// the provider service
        /// </summary>
        private readonly IEncounterService encounterServices;

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

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


        /// <summary>
        /// The account session services.
        /// </summary>
        private readonly IOBEncounterService obEncounterService;

        /// <summary>
        /// The account session services.
        /// </summary>
        private readonly IGynEncounterService gynEncounterService;

        /// <summary>
        /// the aes helper
        /// </summary>
        private readonly IAESHelper aesHelper;

        /// <summary>
        /// The appointments services.
        /// </summary>
        private readonly IAppointmentService appointmentsServices;

        /// <summary>
        /// The account service.
        /// </summary>
        private readonly IAccountService accountService;

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

        /// <summary>
        /// The configuration.
        /// </summary>
        private readonly IAmazonS3Configuration configuration;

        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc />
        public OBEncounterController(
            IOBEncounterService obEncounterService,
            IGynEncounterService gynEncounterService,
            IAppointmentService appointmentsServices,
            IAESHelper aesHelper,
            IDocumentHelper documentHelper,
            IEncounterService encounterServices,
            IPushNotificationHelper pushNotificationHelper,
            IAccountSessionService accountSessionServices,
            IAmazonS3Configuration configuration,
            IAccountService accountService,
             IUnitOfWork unitOfWork)
        {
            this.obEncounterService = obEncounterService;
            this.gynEncounterService = gynEncounterService;
            this.appointmentsServices = appointmentsServices;
            this.aesHelper = aesHelper;
            this.documentHelper = documentHelper;
            this.configuration = configuration;
            this.accountService = accountService;
            this.encounterServices = encounterServices;
            this.pushNotificationHelper = pushNotificationHelper;
            this.accountSessionServices = accountSessionServices;
            this.unitOfWork = unitOfWork;
        }



        /// <summary>
        /// The modify async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Authorize]
        [Route("modify")]
        [ProducesResponseType(typeof(int), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyAsync([FromBody] ob.InsertModel model)
        {
            model = (ob.InsertModel)EmptyFilter.Handler(model);
            int appoitmentId = await this.obEncounterService.getApppointmentId(model.AppointmentId, model.IsAdmission);
            var obEncounterId = appoitmentId == 0 ? await this.obEncounterService.AddAsync(model) : await this.obEncounterService.UpdateAsync(model);
            if ((obEncounterId != null) && (model.Type == OBEncounterType.AncCard))
            {
                CommonEncounterModel commonModel = new CommonEncounterModel();
                commonModel.GPLA = model.JsonString;
                if (model.CommonEncounterId != null)
                {
                    commonModel.CommonEncounterId = (int)model.CommonEncounterId;
                }
                commonModel.AppointmentId = model.AppointmentId;
                commonModel.Type = model.Type;
                commonModel.CreatedBy= model.ModifiedBy;
                var records = this.unitOfWork.Appointments.Find(s => s.AppointmentId == model.AppointmentId);
                int aptId = await this.gynEncounterService.getAptId((int)model.AppointmentId);

                var gynEncounterId = aptId == 0 ? await this.gynEncounterService.InsertCommonEncounter(commonModel) : await this.gynEncounterService.UpdateCommonEncounter(commonModel);
                await this.gynEncounterService.InsertCommonEncounter(commonModel);
            }
            switch (obEncounterId.Response)
            {
                case 0:
                    return this.ServerError();
                default:
                    var basicDetails = await this.encounterServices.GetBasicAppointmentDetails(model.AppointmentId, model.IsAdmission);
                    await this.appointmentsServices.UpdateEncounterTypeAsync(model.AppointmentId,
                        (int)EncounterTypes.OBEncounter, model.IsAdmission);
                    return this.Success(obEncounterId.Response);
            }
        }

        /// <summary>
        /// To find ob encounter dashboard
        /// </summary>
        /// <param name="model" >
        /// The encounter filter model.
        /// </param>
        /// <returns>
        /// The encounter model.
        /// </returns>
        [HttpPost]
        [Authorize]
        [Route("find-dashboard")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindDashboardAsync([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var response = await this.obEncounterService.FindDashboardAsync(appointmentId, model.Type, model.IsAdmission);
            if (response != null)
            {
                response.EncryptedAppointmentId = this.aesHelper.Encode(appointmentId.ToString());
            }
            return this.Success(response);
        }

        /// <summary>
        /// The find gyn encounter.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Authorize]
        [Route("find")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindAsync([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var obEncounter = await this.obEncounterService.FindAsync(appointmentId, model.IsAdmission);
            var providerId = !string.IsNullOrEmpty(model.EncryptedProviderId)
                ? Convert.ToInt32(this.aesHelper.Decode(model.EncryptedProviderId))
                : 0;
            var patientId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedPatientId));
            var appointmentList = new List<AppointmentModel>();
            var oldAppointment = new PreviousAppointmentModel();

            if (!model.IsAdmission)
            {
                var appointments = await this.appointmentsServices.FindByPatientAsync(patientId, providerId);
                appointmentList = appointments.ToList();

                foreach (var item in appointmentList)
                {
                    item.EncryptedAppointmentId = this.aesHelper.Encode(item.AppointmentId.ToString());
                    item.EncryptedPatientId = model.EncryptedPatientId;
                    item.AppointmentTimeString = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd"))
                        .Add(item.AppointmentTime).ToString("hh:mm tt");
                }
            }

            return this.Success(new { Dashboard = obEncounter, Appointments = appointmentList, OldAppointment = oldAppointment });
        }

        /// <summary>
        /// The find full transcript async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [AllowAnonymous]
        [Route("find-full-transcript")]
        [ProducesResponseType(typeof(GynEncounterFullTranscriptModel), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindFullTranscriptAsync([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var obEncounterFullTranscript = await this.obEncounterService.FindFullTranscriptAsync(appointmentId);
            if (obEncounterFullTranscript == null || obEncounterFullTranscript.ObEncounterId == 0)
            {
                return this.BadRequest("Sorry! We don't have a encounter in the system.");
            }

            var additionalData = await this.encounterServices.GetAdditionalProviderDataAsync(appointmentId);

            if (additionalData != null)
            {
                obEncounterFullTranscript.Educations = additionalData.Educations;
                obEncounterFullTranscript.ProviderName = additionalData.ProviderName;
                obEncounterFullTranscript.ProviderNo = additionalData.ProviderNo;
                obEncounterFullTranscript.SpecializationName = additionalData.SpecializationName;
                obEncounterFullTranscript.PracticeName = additionalData.PracticeName;
                obEncounterFullTranscript.PracticeLocation = additionalData.PracticeLocation;
                obEncounterFullTranscript.Signature = additionalData.Signature;
                obEncounterFullTranscript.ClinicPicture = additionalData.ClinicPicture;
            }

            obEncounterFullTranscript.AppointmentTimeString = Convert
                .ToDateTime(DateTime.Now.ToString("yyyy-MM-dd")).Add(obEncounterFullTranscript.AppointmentTime)
                .ToString("hh:mm tt");
            return this.Success(obEncounterFullTranscript);
        }
        /// <summary>
        /// To find ob encounter dashboard
        /// </summary>
        /// <param name="model" >
        /// The encounter filter model.
        /// </param>
        /// <returns>
        /// The encounter model.
        /// </returns>
        [HttpGet]
        [Authorize]
        [Route("calculate-edd")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> CalculateEDD(string value, string lmpStatus)
        {

            DateTime lmp = Convert.ToDateTime(value);
            DateTime edd = DateTime.Now;
            if (lmpStatus == "Known")
            {
                 edd = lmp.AddDays(280);
            }
            if (lmpStatus == "Unknown")
            {
                 edd = lmp.AddDays(-280);
            }
            return this.Success(edd);
        }
        /// <summary>
        /// To calculate GA
        /// </summary>
        /// <param name="model" >
        /// The encounter filter model.
        /// </param>
        /// <returns>
        /// The encounter model.
        /// </returns>
        [HttpGet]
        [Authorize]
        [Route("calculate-ga")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> CalculateGA(string value, string lmpStatus)
        {

            var today = DateTime.Now;
            var lmp = Convert.ToDateTime(value);
            var calculatediff = 0.0;
            if (lmpStatus == "Known")
            {
                calculatediff = Math.Truncate((today.Subtract(lmp).TotalDays));
            }
            if (lmpStatus == "Unknown")
            {
                calculatediff = lmp.Subtract(today).TotalDays;
            }
            var exact = calculatediff - 1.5;
            var ga = Math.Round((exact / 7), 1);
            return this.Success(ga);

        }

        /// <summary>
        /// Inserts the anc card asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Authorize]
        [Route("add-ancCardGeneration")]
        public async Task<ActionResult> InsertAsync([FromBody] ANCCardGenerationModel model, [FromHeader] LocationHeader location)
        {
            model = (ANCCardGenerationModel)EmptyFilter.Handler(model);
            var response = await this.obEncounterService.AddAncAsync(model, location.LocationId);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        [Route("fetch-ancCard")]
        public async Task<ActionResult> FetchAsync(ANCCardGenerationModel model)
        {
            model = (ANCCardGenerationModel)EmptyFilter.Handler(model);
            var response = await this.obEncounterService.FetchAncCardAsync(model);
            return this.Success(response);
        }
        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-anc-card")]
        [AllowAnonymous]
        public async Task<ActionResult> FetchANCAsync(ANCCardGenerationModel model)
        {
            model = (ANCCardGenerationModel)EmptyFilter.Handler(model);
            var response = await this.obEncounterService.FetchPatientAncCardAsync(model);
            return this.Success(response);
        }


        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="patientId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("modify-ancStatus")]
        public async Task<ActionResult> ModifyStaus(int patientId)
        {

            var response = await this.obEncounterService.ModifyStatusAsync(patientId);
            return this.Success(response);
        }

        /// <summary>
        /// To find ob encounter dashboard
        /// </summary>
        /// <param name="model" >
        /// The encounter filter model.
        /// </param>
        /// <returns>
        /// The encounter model.
        /// </returns>
        [HttpPost]
        [AllowAnonymous]
        [Route("find-prescription")]
        [ProducesResponseType(typeof(GynEncounterFullTranscriptModel), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindPrescription([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var obEncounterFullTranscript = await this.obEncounterService.FindPrescriptionAsync(appointmentId);
            if (obEncounterFullTranscript == null || obEncounterFullTranscript.ObEncounterId == 0)
            {
                return this.BadRequest("Sorry! We don't have a encounter in the system.");
            }

            var additionalData = await this.encounterServices.GetAdditionalProviderDataAsync(appointmentId);

            if (additionalData != null)
            {
                obEncounterFullTranscript.Educations = additionalData.Educations;
                obEncounterFullTranscript.ProviderName = additionalData.ProviderName;
                obEncounterFullTranscript.ProviderNo = additionalData.ProviderNo;
                obEncounterFullTranscript.SpecializationName = additionalData.SpecializationName;
                obEncounterFullTranscript.PracticeName = additionalData.PracticeName;
                obEncounterFullTranscript.PracticeLocation = additionalData.PracticeLocation;
                obEncounterFullTranscript.Signature = additionalData.Signature;
                obEncounterFullTranscript.ClinicPicture = additionalData.ClinicPicture;
            }

            obEncounterFullTranscript.AppointmentTimeString = Convert
                .ToDateTime(DateTime.Now.ToString("yyyy-MM-dd")).Add(obEncounterFullTranscript.AppointmentTime)
                .ToString("hh:mm tt");
            return this.Success(obEncounterFullTranscript);
        }

        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="patientId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-order-prescription")]
        [AllowAnonymous]
        public async Task<ActionResult> FetchOrdersAsync(int patientId, string encounterType)
        {

            var response = await this.obEncounterService.FetchOrderPrescription(patientId, encounterType);
            return this.Success(response);
        }


        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="appointmentId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("encouter-completed")]
        public async Task<ActionResult> ModifyEncounterStatus(int appointmentId)
        {

            var response = await this.obEncounterService.ModifyEncounterStatus(appointmentId);
            return this.Success(response);
        }


        /// <summary>
        /// Fetche   all icd values  asynchronous.
        /// </summary>
        [HttpPost]
        [Route("fetch-icdValues")]
        public async Task<ActionResult> FetchICDValuesAsync([FromBody] ICDValuesModel model)
        {
            var response = await this.obEncounterService.FetchICDValues(model);
            return this.Success(response);
        }

        /// <summary>
        /// To find ob encounter dashboard
        /// </summary>
        /// <param name="model" >
        /// The encounter filter model.
        /// </param>
        /// <returns>
        /// The encounter model.
        /// </returns>
        [HttpPost]
        [Authorize]
        [Route("find-ob")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindOb([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var response = await this.obEncounterService.FindOb(appointmentId, model.Type, model.IsAdmission);
            return this.Success(response);
        }


        /// <summary>
        /// Fetch   cross consultation  asynchronous.
        /// </summary>
        [HttpPost]
        [Route("fetch-cross-consultation")]
        public async Task<ActionResult> FetchCrossConsultation([FromBody] ReferralFormModel model)
        {
            if (model.EncryptedAppointmentId != null)
            {
                model.AppointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            }
            var response = await this.obEncounterService.FetchCrossConsultation(model);
            foreach (var item in response)
            {
                item.EncryptedAppointmentId = this.aesHelper.Encode(item.AppointmentId.ToString());
            }
            return this.Success(response);
        }



        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="patientId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("ob-lab-reports")]
        public async Task<ActionResult> FetchObLabReports(int patientId)
        {
            var response = await this.obEncounterService.fetchlabBookingHeader(patientId);
            return this.Success(response);
        }
        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="patientId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        [Route("find-ANC-Visit")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindVisitNo(int patientId)
        {
            var response = await this.obEncounterService.FetchVisitNoAsync(patientId);
            return this.Success(response);
        }

        /// <summary>
        /// Inserts the anc card asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Authorize]
        [Route("add-opinion")]
        public async Task<ActionResult> InserReferralForm([FromBody] ReferralFormModel model)
        {
            model.AppointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var response = await this.obEncounterService.InsertReferralForm(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="patientId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-list-fulltrascript")]
        public async Task<ActionResult> FetchFullTrascriptList(int patientId)
        {

            var response = await this.obEncounterService.FetchFullTrascriptList(patientId);
            foreach (var item in response)
            {
                item.EncryptedAppointmentId = this.aesHelper.Encode(item.AppointmentId.ToString());
            }
            return this.Success(response);
        }


        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="labMainDetailId">The model.</param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        [Route("fetch-lab-parameters")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchLabParameters(int labMainDetailId)
        {
            var response = await this.obEncounterService.FetchLabParameters(labMainDetailId);
            return this.Success(response);
        }

        /// <summary>
        /// The find ob encounter.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("find-encounter")]
        [ProducesResponseType(typeof(EncounterResource), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindEncounterDataAsync([FromBody] ObEncounterFilterModel model)
        {
            model = (ObEncounterFilterModel)EmptyFilter.Handler(model);
            var appointmentId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAppointmentId));
            var obEncounter = await this.obEncounterService.FindEncounterDataAsync(appointmentId, model.IsAdmission);
            var providerId = !string.IsNullOrEmpty(model.EncryptedProviderId)
                ? Convert.ToInt32(this.aesHelper.Decode(model.EncryptedProviderId))
                : 0;
            var patientId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedPatientId));
            var appointmentList = new List<AppointmentModel>();
            var oldAppointment = new PreviousAppointmentModel();

            if (!model.IsAdmission)
            {
                var appointments = await this.appointmentsServices.FindByPatientAsync(patientId, providerId);
                appointmentList = appointments.ToList();

                foreach (var item in appointmentList)
                {
                    item.EncryptedAppointmentId = this.aesHelper.Encode(item.AppointmentId.ToString());
                    item.EncryptedPatientId = model.EncryptedPatientId;
                    item.AppointmentTimeString = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd"))
                        .Add(item.AppointmentTime).ToString("hh:mm tt");
                }
            }

            return this.Success(new { Dashboard = obEncounter, Appointments = appointmentList, OldAppointment = oldAppointment });
        }
    }
}


