using Hims.Api.Models;
using Hims.Api.Utilities;
using Hims.Domain.Services;
using Hims.Shared.DataFilters;
using Hims.Shared.EntityModels;
using Hims.Shared.Library.Enums;
using Hims.Shared.UserModels;
using Hims.Shared.UserModels.PatientMedication;
using Hims.Shared.UserModels.Pharmacy;
using Hims.Shared.UserModels.Vaccine;
using Hims.Shared.UserModels.WebNotification;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Hims.Api.Controllers
{
    /// <inheritdoc />
    [Authorize]
    [Route("api/vaccine")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class VaccineController : BaseController
    {
        /// <summary>
        /// The vaccine service.
        /// </summary>
        private readonly IVaccineService vaccineService;

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

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

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


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


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

        /// <inheritdoc />
        public VaccineController(IVaccineService vaccineService, IPatientService patientService, IPharmacyService pharmacyService, IWebNotificationService webNotificationService, IPatientEncounterService patientEncounterService, IAppointmentService appointmentsServices)
        {
            this.vaccineService = vaccineService;
            this.patientService = patientService;
            this.pharmacyService = pharmacyService;
            this.webNotificationService = webNotificationService;
            this.patientEncounterService = patientEncounterService;
            this.appointmentsServices = appointmentsServices;
        }

        /// <summary>
        /// Modifies the vaccine group asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("modify-vaccine-group")]
        public async Task<ActionResult> ModifyVaccineGroupAsync([FromBody] VaccineGroupModel model)
        {
            model = (VaccineGroupModel)EmptyFilter.Handler(model);
            var res = await this.vaccineService.ModifyVaccineGroupAsync(model);
            return this.Success(res);
        }

        /// <summary>
        /// Fetches all vaccine group asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-all-vaccine-group")]
        public async Task<ActionResult> FetchAllVaccineGroupAsync([FromBody] VaccineGroupModel model)
        {
            model ??= new VaccineGroupModel();
            var res = await this.vaccineService.GetAllVaccineGroupsAsync(model);
            return this.Success(res);
        }

        /// <summary>
        /// Deletes the vaccine group asynchronous.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("delete-group")]
        public async Task<ActionResult> DeleteVaccineGroupAsync(int id)
        {
            try
            {
                return this.Success(await this.vaccineService.DeleteVaccineGroupAsync(id));
            }
            catch (Exception)
            {
                return this.BadRequest("Can't be deleted because this group is linked with vaccine masters.");
            }
        }

        /// <summary>
        /// Modifies the vaccine master asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("modify-vaccine-master")]
        public async Task<ActionResult> ModifyVaccineMasterAsync([FromBody] VaccineMasterModel model)
        {
            model = (VaccineMasterModel)EmptyFilter.Handler(model);
            var res = await this.vaccineService.ModifyVaccineMaster(model);
            return this.Success(res);
        }

        /// <summary>
        /// Fetches the vaccine master asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-vaccine-master")]
        public async Task<ActionResult> FetchVaccineMasterAsync([FromBody] VaccineMasterModel model)
        {
            model ??= new VaccineMasterModel();
            var res = await this.vaccineService.FetchVaccineMastersAsync(model);
            return this.Success(res);
        }

        /// <summary>
        /// Fetches all vaccine types asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-vaccine-type")]
        public async Task<ActionResult> FetchAllVaccineTypesAsync()
        {
            var res = await this.vaccineService.FetchAllVaccineTypesAsync();
            return this.Success(res);
        }

        /// <summary>
        /// Updates the vaccine master sequence asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("set-vaccine-master-order")]
        public async Task<ActionResult> UpdateVaccineMasterSequenceAsync([FromBody] List<VaccineMasterModel> model)
        {
            if (model.Count == 0)
            {
                return this.BadRequest("No order found..!!");
            }

            var res = await this.vaccineService.SetVaccineMasterOrderAsync(model);
            return this.Success(res);
        }

        /// <summary>
        /// Modifies the vacine master status asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("modify-vaccine-master-status")]
        public async Task<ActionResult> ModifyVacineMasterStatusAsync([FromBody] VaccineMasterModel model)
        {
            model = (VaccineMasterModel)EmptyFilter.Handler(model);
            var response = await this.vaccineService.ChangeVaccineActiveStatusAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the immunization history asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("get-immunization-schedule")]
        public async Task<ActionResult> FetchImmunizationHistoryAsync([FromBody] VaccineMasterModel model)
        {
            model = (VaccineMasterModel)EmptyFilter.Handler(model);
            var getPatientDetail = await this.patientService.FindAsync((int)model.PatientId);
            if (getPatientDetail == null)
            {
                return this.BadRequest("No patient found");
            }
            if (getPatientDetail.DateOfBirth == null)
            {
                return this.BadRequest("Patient date of birth is not added please add to continue");
            }
            model.Active = true;
            var getVaccines = await this.vaccineService.FetchVaccineMastersAsync(model);

            foreach (var vaccine in getVaccines)
            {
                switch (vaccine.AllowedType)
                {
                    case "days":
                        var calDays = (int)vaccine.AllowedDays;
                        vaccine.ScheduledDate = Convert.ToDateTime(getPatientDetail.DateOfBirth).AddDays(calDays);
                        break;
                    case "weeks":
                        var week = (int)vaccine.AllowedDays;
                        var weekToDay = week * 7;
                        vaccine.ScheduledDate = Convert.ToDateTime(getPatientDetail.DateOfBirth).AddDays(weekToDay);
                        break;
                    case "months":
                        var month = (int)vaccine.AllowedDays;
                        vaccine.ScheduledDate = Convert.ToDateTime(getPatientDetail.DateOfBirth).AddMonths(month);
                        break;
                    case "years":
                        var getYear = (vaccine.AllowedDays).ToString().Split(".");
                        var wholeYear = Convert.ToInt32(getYear[0]);
                        var wholeMonth = 0;
                        if (getYear.Length == 2)
                        {
                            wholeMonth = Convert.ToInt32(getYear[1]);
                        }
                        var getYearDate = Convert.ToDateTime(getPatientDetail.DateOfBirth).AddYears(wholeYear);
                        if (wholeMonth > 0)
                        {
                            var monthDate = getYearDate.AddMonths(wholeMonth);
                            getYearDate = monthDate;
                        }
                        vaccine.ScheduledDate = getYearDate;
                        break;
                }
                vaccine.AllowedLapsDate = vaccine.AllowedLapsDays != null ? Convert.ToDateTime(vaccine.ScheduledDate).AddDays((int)vaccine.AllowedLapsDays) : vaccine.ScheduledDate;
            }
            return this.Success(getVaccines);
        }

        /// <summary>
        /// Fetches the vaccine age group asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-vaccine-age-group")]
        public async Task<ActionResult> FetchVaccineAgeGroupAsync()
        {
            return this.Success(await this.vaccineService.FetchVaccineAgeGroupAsync());
        }

        /// <summary>
        /// Links the pharmacy with vaccines asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("modify-pharmacy-link")]
        public async Task<ActionResult> LinkPharmacyWithVaccinesAsync([FromBody] VaccinePharmacyLinkHeaderModel model)
        {
            model = (VaccinePharmacyLinkHeaderModel)EmptyFilter.Handler(model);
            var response = await this.vaccineService.ModifyVaccinePharmacyLinkAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the pharmacy link asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-pharmacy-link")]
        public async Task<ActionResult> FetchPharmacyLinkAsync([FromBody] VaccinePharmacyLinkHeaderModel model)
        {
            model ??= new VaccinePharmacyLinkHeaderModel();
            var response = await this.vaccineService.FetchVaccinePharmaLinkAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Deletes the pharmacy vaccine link asynchronous.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("delete-pharmacy-link")]
        public async Task<ActionResult> DeletePharmacyVaccineLinkAsync(int id)
        {
            if (id == 0)
            {
                return this.BadRequest("Invalid request made.");
            }

            return this.Success(await this.vaccineService.DeletePharmacyLinkAsync(id));
        }

        /// <summary>
        /// Fetches the vaccine with pharmacy stock for order asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-vaccines-for-order")]
        public async Task<ActionResult> FetchVaccineWithPharmacyStockForOrderAsync([FromBody] VaccinePharmacyLinkDetailModel model, [FromHeader] LocationHeader location)
        {
            model = (VaccinePharmacyLinkDetailModel)EmptyFilter.Handler(model);
            var vaccineWithProduct = await this.vaccineService.FetchVaccinesWithPharmacyProductInformationAsync(model.VaccineMasterId);

            var requestRetail = new RetailPharmacyModel { LocationId = Convert.ToInt32(location.LocationId) };
            var prod = new List<PediatricImmunizationTempModel>();
            var retailStoreAtLocation = await this.pharmacyService.FetchAllRetailStores(requestRetail);
            foreach (var item in vaccineWithProduct)
            {
                var tempProd = new PediatricImmunizationTempModel();
                tempProd.VaccineDetail = new VaccinePharmacyLinkDetailModel();
                tempProd.VaccineDetail = item;
                tempProd.Stocks = new List<ProductModel>();
                foreach (var store in retailStoreAtLocation)
                {

                    var requestStock = new ProductModel
                    {
                        RetailPharmacyId = store.RetailPharmacyId,
                        PharmacyProductId = item.PharmacyProductId
                    };

                    var stockRes = await this.pharmacyService.FetchPharmacyProductWithRetailStockAsync(requestStock);
                    foreach (var stock in stockRes)
                    {
                        stock.RetailName = store.RetailName;
                        tempProd.Stocks.Add(stock);
                    }
                }
                prod.Add(tempProd);
            }

            return this.Success(prod);
        }

        /// <summary>
        /// Orders the vaccine asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("order-vaccine")]
        public async Task<ActionResult> OrderVaccineAsync([FromBody] ImmunizationHistoryModel model)
        {
            model = (ImmunizationHistoryModel)EmptyFilter.Handler(model);
            var history = await this.vaccineService.AddImmunizationOrderAsync(model);
            if (history > 0)
            {
                var checkMed = (await this.patientEncounterService.FetchPatientMedication(new PatientMedicationHeaderModel { AppointmentId = model.AppointmentId })).ToList();

                var not = new PatientMedicationHeaderModel
                {
                    Active = true,
                    AppointmentId = model.AppointmentId,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    EncounterType = "pediatric-encounter"
                };
                if (checkMed.Count > 0)
                {
                    not.PatientMedicationHeaderId = checkMed[0].PatientMedicationHeaderId;
                }

                not.Medicines = new List<PatientMedicationDetailModel>();
                var med = new PatientMedicationDetailModel
                {
                    AfternoonDosage = string.Empty,
                    Duration = 1,
                    DurationType = "D",
                    IsAfternoon = false,
                    IsMorning = true,
                    IsNight = false,
                    MorningDosage = "Injection",
                    NightDosage = string.Empty,
                    PharmacyProductId = (int)model.PharmacyProductId,
                    Dosage = 1,
                    Instruction = string.Empty,
                    Route = "Intra Muscular"
                };
                not.Medicines.Add(med);

                var medicationHeader = await this.patientEncounterService.AddPatientMedicationAsync(not);
                if (medicationHeader > 0)
                {
                    try
                    {
                        await this.appointmentsServices.UpdateEncounterTypeAsync(model.AppointmentId,
                               (int)EncounterTypes.PediatricEncounter, false);

                        var appointment = await this.appointmentsServices.FindAppointmentAsync(model.AppointmentId, false);
                        var url = "app/pharmacy/sales-bill";
                        var roles = (await this.webNotificationService.GetAllRoles()).ToList();
                        var getRolesToNotify = roles.Where(r => r.RoleName.ToLower().Contains("pharm"));
                        var getAdmins = roles.Where(r => r.RoleName.ToLower().Contains("admin"));
                        var finalRoleModel = new List<RoleModel>();
                        finalRoleModel.AddRange(getRolesToNotify.ToList());
                        finalRoleModel.AddRange(getAdmins.ToList());
                        var notification = new WebNotificationModel
                        {
                            AllowedAccounts = string.Empty,
                            AllowedRoles = string.Join(",", finalRoleModel.Select(r => r.RoleId)),
                            CreatedDate = DateTime.Now,
                            IsRead = false,
                            Message = $@"{appointment.ProviderName} prescribed medicine",
                            RedirectionLink = url,
                            WebNotificationLogTypeId = (int)WebNotificationLogType.View,
                            WebNotificationPriorityId = (int)WebNotificationPriority.High,
                            PatientId = model.PatientId,
                            ReferenceId = model.AppointmentId,
                            ModulesMasterId = (int)ModulesMasterType.Pharmacy
                        };
                        await this.webNotificationService.InsertAsync(notification);
                    }
                    catch (Exception ex)
                    {
                        // ignore
                    }
                }
            }
            return this.Success(history);
        }

        /// <summary>
        /// Checks the product from sales bill asynchronous.
        /// </summary>
        /// <param name="patientId">The patient identifier.</param>
        /// <param name="pharmacyProductId">The pharmacy product identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("check-vaccine-product")]
        public async Task<ActionResult> CheckProductFromSalesBillAsync(int patientId, string pharmacyProductId)
        {
            if (string.IsNullOrEmpty(pharmacyProductId) && patientId == 0) { return this.BadRequest("Invalid parameter passed."); }
            var response = await this.vaccineService.CheckProductFromSalesBillAsync(patientId, pharmacyProductId);
            return this.Success(response);
        }

        [HttpPost]
        [Route("give-vaccine")]
        public async Task<ActionResult> GiveVaccinationAsync([FromBody] ImmunizationHistoryModel model)
        {
            model = (ImmunizationHistoryModel)EmptyFilter.Handler(model);
            var response = await this.vaccineService.GiveVaccineAsync(model);
            return this.Success(response);
        }

        [HttpGet]
        [Route("fetch-patient-immunization-history")]
        public async Task<ActionResult> FetchImmunizationHistoryOfPatientAsync(int patientId)
        {
            if(patientId == 0) { return this.BadRequest("Invalid request."); }
            var response = await this.vaccineService.FetchImmunizationHistoryAsync(patientId);
            return this.Success(response);
        }
    }

    /// <summary>
    /// The temp model.
    /// </summary>
    public class PediatricImmunizationTempModel
    {
        /// <summary>
        /// Gets or sets the vaccine detail.
        /// </summary>
        /// <value>
        /// The vaccine detail.
        /// </value>
        public VaccinePharmacyLinkDetailModel VaccineDetail { get; set; }

        /// <summary>
        /// Gets or sets the stocks.
        /// </summary>
        /// <value>
        /// The stocks.
        /// </value>
        public List<ProductModel> Stocks { get; set; }
    }
}
