using System;
using Hims.Shared.UserModels.Common;
using Hims.Shared.UserModels.FinalBill;

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

    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Entities;
    using Hims.Domain.Helpers;
    using Hims.Infrastructure.Services;
    using Hims.Shared.EntityModels;
    using Hims.Shared.Library.Enums;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Utilities;

    /// <inheritdoc />
    [Authorize]
    [Route("api/final-bill")]
    public class FinalBillController : BaseController
    {
        /// <summary>
        /// The service
        /// </summary>
        private readonly IFinalBillService service;

        /// <summary>
        /// The service order service
        /// </summary>
        private readonly IServiceOrderService serviceOrderService;
        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <summary>
        /// the provider service
        /// </summary>
        private readonly IPatientService patientServices;

        /// <summary>
        /// the module service
        /// </summary>
        private readonly IPackageModuleService packageModuleServices;

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

        /// <inheritdoc />
        public FinalBillController(IFinalBillService service, IAESHelper aesHelper, IServiceOrderService serviceOrderService, IAuditLogService auditLogServices, IPatientService patientServices, IPackageModuleService packageModuleServices)
        {
            this.service = service;
            this.serviceOrderService = serviceOrderService;
            this.auditLogServices = auditLogServices;
            this.patientServices = patientServices;
            this.packageModuleServices = packageModuleServices;
            this.aesHelper = aesHelper;
        }

        /// <summary>
        /// Gets the basics asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("get-basics")]
        public async Task<ActionResult> GetBasicsAsync([FromBody] FilterModel model)
        {
            try
            {
                model.AdmissionId = Convert.ToInt32(model.Id);
                var response = await this.service.GetBasicAsync(model).ConfigureAwait(false);

                if (model.IsAdmission)
                {
                    var isDischargedDate = await this.service.IsDischargedAsync(model).ConfigureAwait(false);
                    response.IsDischarged = isDischargedDate != null;
                    response.DischargeDate = isDischargedDate;
                }

                var totalPaid = await this.serviceOrderService.GetTotalPaidAsync(new Shared.UserModels.ServiceOrder.FilterModel
                {
                    AdmissionId = model.AdmissionId,
                    IsAdmission = model.IsAdmission
                });
                response.TotalAmountPaid = totalPaid;
                response.PendingAmount = response.TotalAmountPaid - response.FinalAmount;

                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Success,
                    Data = response
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// Inserts the asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchAsync([FromBody] FilterModel model)
        {
            try
            {
                model.AdmissionId = Convert.ToInt32(model.Id);
                var response = await this.service.FetchAsync(model).ConfigureAwait(false);
                var chargeId = await this.service.GetDefaultChargeId();

                if(response != null)
                {
                    foreach (var item in response.PackageRecords)
                    {
                        var details = await packageModuleServices.GetChargeCategoryTotalAsync(chargeId, item.PackageModuleId, item.LocationId, item.ChargeModuleTemplateId, item.ModulesMasterIds);
                        if (response != null)
                            item.Total = details.Item1 - details.Item3;
                    }
                }

                return Ok(new GenericResponse
                {
                    Status = response != null ? GenericStatus.Success : GenericStatus.Info,
                    Data = response
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// Inserts the asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("insert")]
        public async Task<ActionResult> InsertAsync([FromBody] InsertModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                model.AdmissionId = Convert.ToInt32(model.Id);//
                model.LocationId = Convert.ToInt32(header.LocationId);
                var response = await this.service.InsertAsync(model).ConfigureAwait(false);
                if (response > 0)
                {
                    await this.service.UpdatePackageCompleteness(model.AdmissionId, model.IsAdmission, true);
                    try
                    {
                        var idModel = new IdModel()
                        {
                            Id = Convert.ToInt32(model.Id),
                            IsAdmission = model.IsAdmission,
                        };
                        var result = await this.service.FetchFinalBillDetailsAsync(idModel);

                        var auditLogModel = new AuditLogModel
                        {
                            AccountId = model.CreatedBy,
                            LogTypeId = (int)LogTypes.Services,
                            LogFrom = (short)model.RoleId,
                            LogDate = DateTime.UtcNow,
                            LogDescription = $@"{model.FullName}<b> Generated Final-Bill</b> with  Bill No.:<b>FN{result.FinalBillId.ToString().PadLeft(6, '0')}</b><br> for the Patient:<b>{result.FullName}</b>",
                            LocationId= Convert.ToInt32(header.LocationId)
                        };
                        await this.auditLogServices.LogAsync(auditLogModel);
                    }
                    catch(Exception e)
                    {
                        //audit
                    }

                }
                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Error,
                    Data = response
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }

        /// <summary>
        /// Inserts the asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("cancel")]
        public async Task<ActionResult> CancelAsync([FromBody] FilterModel model, [FromHeader] LocationHeader header)
        {
            try
            {
                model.AdmissionId = Convert.ToInt32(model.Id);
                var response = await this.service.CancelAsync(model).ConfigureAwait(false);
                if (response > 0)
                {
                    await this.service.UpdatePackageActivity(model.AdmissionId,model.IsAdmission,true);
                    try
                    {
                        var idModel = new IdModel()
                        {
                            Id = Convert.ToInt32(model.Id),
                            IsAdmission = model.IsAdmission,
                        };
                        var result = await this.service.FetchFinalBillDetailsAsync(idModel);
                        var auditLogModel = new AuditLogModel
                        {
                            AccountId = model.CreatedBy,
                            LogTypeId = (int)LogTypes.Services,
                            LogFrom = (short)model.RoleId,
                            LogDate = DateTime.UtcNow,
                            LogDescription = $@"{model.FullName}<b> Cancelled Final-Bill</b> of Bill No.:<b>FN{result.FinalBillId.ToString().PadLeft(6, '0')}</b> <br>for the Patient:<b>{result.FullName}</b>",
                            LocationId= Convert.ToInt32(header.LocationId)
                        };
                        await this.auditLogServices.LogAsync(auditLogModel);
                    }
                    catch (Exception e)
                    {
                        //audit
                    }

                }

                return Ok(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Error,
                    Data = response
                });
            }
            catch (Exception ex)
            {
                return Ok(new GenericResponse
                {
                    Status = GenericStatus.Error,
                    Message = ex.Message
                });
            }
        }
    }
}