
namespace Hims.Api.Controllers
{
    using System;
    using System.Threading.Tasks;
    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Repositories.UnitOfWork;
    using Hims.Shared.DataFilters;
    using Hims.Shared.Library.Enums;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Shared.EntityModels;
    using Utilities;

    /// <inheritdoc />
    [Authorize]
    [Route("api/health-card")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class HealthCardController : BaseController
    {

        /// <summary>
        /// The auditlog services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <summary>
        /// The admission services.
        /// </summary>
        private readonly IHealthCardService healthCardService;
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc />
        public HealthCardController(
            IAuditLogService auditLogServices,
            IHealthCardService healthCardService,
            IUnitOfWork unitOfWork)
        {

            this.auditLogServices = auditLogServices;
            this.healthCardService = healthCardService;
            this.unitOfWork = unitOfWork;
        }

        /// <summary>
        /// The fetch cubicles.
        /// </summary>
        /// <param name="model">
        /// The widget filter model.
        /// </param>
        /// <returns>
        /// The list of cubicle.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - List of cubicles.
        /// - 500 - Problem with Server side code.
        /// </remarks>

        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchAsync([FromBody] HealthCardModel model)
        {
            model = (HealthCardModel)EmptyFilter.Handler(model);

            var response = await this.healthCardService.FetchAllAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The insert cubicle async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add")]
        public async Task<ActionResult> InsertAsync([FromBody] HealthCardModel model, [FromHeader] LocationHeader header)
        {
            model = (HealthCardModel)EmptyFilter.Handler(model);

            var response = await this.healthCardService.InsertAsync(model);
            switch (response)
            {
                case -1:
                    return this.Conflict("Given Health Card has already been exists.");
                case 0:
                    return this.ServerError();
            }
            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.CreatedBy,
                    LogTypeId = (int)LogTypes.HealthCard,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $" {model.ModifiedByName} has added <b>Health Card</b> - <b>{model.HealthCardName}</b>",
                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);
            }
            return this.Success(response);
        }

        /// <summary>
        /// The update widget async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("update")]
        public async Task<ActionResult> UpdateAsync([FromBody] HealthCardModel model, [FromHeader] LocationHeader header)
        {
            model = (HealthCardModel)EmptyFilter.Handler(model);

            var response = await this.healthCardService.UpdateAsync(model);
            switch (response)
            {
                case -1:
                    return this.Conflict("Given Health Card has already been exists.");
                case 0:
                    return this.ServerError();
            }
            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.ModifiedBy,
                    LogTypeId = (int)LogTypes.HealthCard,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $"<b> {model.ModifiedByName}</b> has updated Health Card - <b>{model.HealthCardName}</b>",
                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);
            }
            return this.Success(response);
        }

        [HttpPost]
        [Route("modify-status")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(409)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyStatusAsync([FromBody] HealthCardModel model, [FromHeader] LocationHeader header)
        {
            model = (HealthCardModel)EmptyFilter.Handler(model);
            var response = await this.healthCardService.ActivateOrDeactivateCard(model);
            if (response == 0)
            {
                return this.ServerError();
            }
            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.ModifiedBy,
                    LogTypeId = (int)LogTypes.HealthCard,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = model.Active == true ? $@"<b>{model.ModifiedByName}</b> has Activated status of HealthCard <br/>name:<b> '{model.HealthCardName}'</b> on {DateTime.UtcNow.AddMinutes(330)}" : $@"<b>{model.ModifiedByName}</b> has Deactivated status of IdProof<br/>name: <b>'{model.HealthCardName}'</b> on {DateTime.UtcNow.AddMinutes(330)}",

                    LocationId = Convert.ToInt32(header.LocationId)
                };
                await this.auditLogServices.LogAsync(auditLogModel);
            }
            return this.Success(response);

        }

        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-issued-cards")]
        public async Task<ActionResult> FetchAllIssuedCardAsync([FromBody] HealthCardHolderModel model)
        {
            var response = await this.healthCardService.FetchAllIssuedCard(model);
            return this.Success(response);
        }


        /// <summary>
        /// Inserts the hoc asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-new-card")]
        public async Task<ActionResult> IssueNewCardAsync([FromBody] HealthCardHolderModel model, [FromHeader] LocationHeader header)
        {
            model = (HealthCardHolderModel)EmptyFilter.Handler(model);
            var response = await this.healthCardService.AddNewCardAsync(model);
            var healCardDetais = this.unitOfWork.HealthCards.Find(s => s.HealthCardId == model.HealthCardId);
            var patientDetails = this.unitOfWork.Patients.Find(s => s.PatientId == model.PatientId);
            if (response < 0)
            {
                return this.BadRequest("The Patient already exists health card.");
            }
            if (response > 0)
            {
                var auditLogModel = new AuditLogModel
                {
                    AccountId = model.CreatedBy,
                    LogTypeId = (int)LogTypes.HealthCard,
                    LogFrom = (int)AccountType.Administrator,
                    LogDate = DateTime.UtcNow,
                   LogDescription = $"<b> {model.CreatedByName}</b>{(model.IssueHealthCardId == 0 ? "Added" : "Updated")}  <strong>{healCardDetais.HealthCardName}</strong> to a <strong>{patientDetails.FullName}</strong> patient",
                   LocationId = Convert.ToInt32(header.LocationId)
               };
                await this.auditLogServices.LogAsync(auditLogModel);
            }

            return this.Success(response);
        }

        /// <summary>
        /// Fetches all asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("card-details")]
        public async Task<ActionResult> FetchCardAsync([FromBody] HealthCardHolderModel model)
        {
            model ??= new HealthCardHolderModel();
            var response = await this.healthCardService.FetchCardBeneficiariesAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Checks the patient health card exists asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("check-patient-health-card-exist")]
        public async Task<ActionResult> CheckPatientHealthCardExistsAsync([FromBody] HealthCardHolderModel model)
        {
            model ??= new HealthCardHolderModel();
            var response = await this.healthCardService.CheckHealthCardForPatient(model);
            return this.Success(response);
        }

        /// <summary>
        /// Checks the patient health card exists asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-health-card")]
        public async Task<ActionResult> CheckPatientHealthCardDetailAsync([FromBody] HealthCardHolderModel model)
        {
            model ??= new HealthCardHolderModel();
            var response = await this.healthCardService.FetchPatientIssuedCard(model.PatientId);
            return this.Success(response);
        }
    }
}