namespace Hims.Api.Controllers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    using Domain.Services;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels.Common;
    using Hims.Shared.UserModels.PharmacyRequest;
    using Hims.Shared.UserModels.OperationTheater;

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;

    using Shared.DataFilters;
    using Shared.EntityModels;
    using Utilities;
    using Hims.Api.Models;

    /// <summary>
    /// The pharmacy request controller.
    /// </summary>
    [Authorize]
    [Route("api/pharmacy-request")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class PharmacyRequestController : BaseController
    {
        /// <summary>
        /// The pharmacy request service.
        /// </summary>
        private readonly IPharmacyRequestService pharmacyRequestService;

        /// <summary>
        /// The pharmacy log service.
        /// </summary>
        private readonly IPharmacyLogService pharmacyLogService;

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

        /// <summary>
        /// The service
        /// </summary>
        private readonly IReceiptService receiptService;

        /// <inheritdoc />
        public PharmacyRequestController(IPharmacyRequestService pharmacyRequestService, IPharmacyLogService pharmacyLogService, IPatientService patientServices, IReceiptService receiptService)
        {
            this.pharmacyRequestService = pharmacyRequestService;
            this.pharmacyLogService = pharmacyLogService;
            this.patientServices = patientServices;
            this.receiptService = receiptService;
        }

        /// <summary>
        /// The add pharmacy indent.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="location"></param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-indent")]
        public async Task<ActionResult> AddPharmacyIndent([FromBody] IndentRequestModel model, [FromHeader] LocationHeader location)
        {
            model = (IndentRequestModel)EmptyFilter.Handler(model);
            model.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            model.ProductName = model.PharmacyProductId != null ? await this.pharmacyRequestService.FindProductByPharmacyProduct((int)model.PharmacyProductId) : model.ProductName;
            var response = await this.pharmacyRequestService.AddIndentRequest(model);            
            var patientFullName = await this.patientServices.FindPatientByAdmissionId(model.AdmissionId);
            var pharmacyLogModel = new PharmacyLogModel
            {
                AccountId = model.CreatedBy,
                PharmacyLogTypeId = (int)PharmacyLogTypes.Pharmacy_Indent,
                LogFrom = (short)model.RoleId,
                LogDate = DateTime.Now,
                LocationId=model.LocationId,
                LogDescription = $@"Pharmacy Indent Request Added Successfully by <b>{model.CreatedByName}</b> to Patient <b>{patientFullName}<b/><br/>Product Name:'{model.ProductName}'<br/>Quantity:'{model.Quantity}'"
            };
            await this.pharmacyLogService.LogAsync(pharmacyLogModel);

            return response > 0 ? this.Success(response) : this.ServerError();
        }

        /// <summary>
        /// The add pharmacy indent.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("reject-indent-product")]
        public async Task<ActionResult> RejectPharmacyProductIndent([FromBody] PharmacyIssueRejectRequest model, [FromHeader] LocationHeader location)
        {
            model = (PharmacyIssueRejectRequest)EmptyFilter.Handler(model);
           // model.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            var response = await this.pharmacyRequestService.RejectPharmacyProductIndent(model.PharmacyIndentHeaderId, model.PharmacyIndentDetailId,model.CreatedBy);
            var pharmacyLogModel = new PharmacyLogModel
            {
                AccountId = model.CreatedBy,
                PharmacyLogTypeId = (int)PharmacyLogTypes.Pharmacy_Indent,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.Now,
                LocationId= int.Parse(location.LocationId),
                LogDescription = $@"Pharmacy Indent Request for Product Name:'{model.ProductName}' has been Rejected Successfully by <b>{model.CreatedByName}</b>"
            };
            await this.pharmacyLogService.LogAsync(pharmacyLogModel);

            return response > 0 ? this.Success(response) : this.ServerError();
        }

        /// <summary>
        /// The add pharmacy indent.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("delete-indent")]
        public async Task<ActionResult> CancelPharmacyIndent([FromBody] IndentRequestModel model, [FromHeader] LocationHeader location)
        {
            model = (IndentRequestModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.CancelIndentRequest(model.PharmacyIndentHeaderId, model.PharmacyIndentDetailId);
            var pharmacyProduct = model.PharmacyProductId != null ? await this.pharmacyRequestService.FindProductByPharmacyProduct((int)model.PharmacyProductId) : model.ProductName;
            var patientFullName = await this.patientServices.FindPatientByAdmissionId(model.AdmissionId);
            var pharmacyLogModel = new PharmacyLogModel
            {
                AccountId = model.CreatedBy,
                PharmacyLogTypeId = (int)PharmacyLogTypes.Pharmacy_Indent,
                LogFrom = (short)model.RoleId,
                LogDate = DateTime.Now,
                LocationId= int.Parse(location.LocationId),
                LogDescription = $@"Pharmacy Indent Request Deleted Successfully by <b>{model.CreatedByName}</b> to Patient <b>{patientFullName}<b/><br/>Product Name:'{pharmacyProduct}'"
            };
            await this.pharmacyLogService.LogAsync(pharmacyLogModel);

            return response > 0 ? this.Success(response) : this.ServerError();
        }

        /// <summary>
        /// The add pharmacy indent.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="location"></param>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-indent-bulk")]
        public async Task<ActionResult> AddBulkPharmacyIndent([FromBody] List<IndentRequestModel> data, [FromHeader] LocationHeader location)
        {
            try
            {
                data = (List<IndentRequestModel>)EmptyFilter.Handler(data);
                var response = 0;
                var indentDate = DateTime.Now;
                var requiredDate = DateTime.Now;
                var departmentId = await this.patientServices.GetDepartmentIdByAdmissionId(data[0].AdmissionId);
                foreach (var model in data)
                {
                    model.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
                    model.IndentDate = indentDate;
                    model.RequiredDate = indentDate;
                    model.DepartmentId = departmentId;
                    response += await this.pharmacyRequestService.AddIndentRequest(model);
                    var pharmacyProduct = model.PharmacyProductId != null ? await this.pharmacyRequestService.FindProductByPharmacyProduct((int)model.PharmacyProductId) : model.ProductName;
                    var patientFullName = await this.patientServices.FindPatientByAdmissionId(model.AdmissionId);
                    var pharmacyLogModel = new PharmacyLogModel
                    {
                        AccountId = model.CreatedBy,
                        PharmacyLogTypeId = (int)PharmacyLogTypes.Pharmacy_Indent,
                        LogFrom = (short)model.RoleId,
                        LogDate = DateTime.Now,
                        LocationId = model.LocationId,
                        LogDescription = $@"Pharmacy Indent Request Added Successfully by <b>{model.CreatedByName}</b> to Patient <b>{patientFullName}<b/><br/>Product Name:'{pharmacyProduct}'<br/>Quantity:'{model.Quantity}'"
                    };
                    await this.pharmacyLogService.LogAsync(pharmacyLogModel);
                }

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

        /// <summary>
        /// The fetch pharmacy indent header.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="location"></param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-indent-header")]
        public async Task<ActionResult> FetchPharmacyIndentHeader([FromBody] PharmacyIndentHeaderModel model, [FromHeader] LocationHeader location)
        {
            model = (PharmacyIndentHeaderModel)EmptyFilter.Handler(model);
            model.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            var response = await this.pharmacyRequestService.FetchPharmacyHeader(model);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch pharmacy indent detail.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-indent-detail")]
        public async Task<ActionResult> FetchPharmacyIndentDetail([FromBody] PharmacyIndentHeaderModel model)
        {
            model = (PharmacyIndentHeaderModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.FetchPharmacyDetail(model.PharmacyIndentHeaderId);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch all pending indent.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="location"></param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-all-indent")]
        public async Task<ActionResult> FetchAllPendingIndent([FromBody] PharmacyIndentHeaderModel model, [FromHeader] LocationHeader location)
        {
            model = (PharmacyIndentHeaderModel)EmptyFilter.Handler(model);
            model.LocationId = !string.IsNullOrEmpty(location.LocationId) ? int.Parse(location.LocationId) : (int?)null;
            var response = await this.pharmacyRequestService.FetchAllPendingIndent(model);
            return this.Success(response);
        }

        /// <summary>
        /// The approve pending indent async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("approve-pending-indent")]
        public async Task<ActionResult> ApprovePendingIndentAsync([FromBody] PharmacyIssueRequest model, [FromHeader] LocationHeader location)
        {
            model = (PharmacyIssueRequest)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.IssueIndentBillAsync(model);

            if (response > 0 && model.ReceiptId > 0)
            {
                var subResponse = await this.receiptService.InsertAsync(new Shared.UserModels.Receipt.InsertModel
                {
                    ReceiptId = model.ReceiptId ?? 0,
                    AdmissionId = model.AdmissionId ?? 0,
                    Cost = Math.Round(model.Total, 2),
                    CreatedBy = model.CreatedBy
                });
            }

            var pharmacyLogModel = new PharmacyLogModel
            {
                AccountId = model.LoginAccountId,
                PharmacyLogTypeId = (int)PharmacyLogTypes.Pharmacy_Issue,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.Now,
                LocationId = int.Parse(location.LocationId),
                LogDescription = $@"Pharmacy Indent Request Approved Successfully.<br/>Product Name:'{model.ProductName}'<br/>Quantity:'{model.Quantity}'"
            };
            await this.pharmacyLogService.LogAsync(pharmacyLogModel);

            return this.Success(response);
        }

        /// <summary>
        /// The get issued pharmacy indents async.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("get-issue-indent-detail")]
        public async Task<ActionResult> GetIssuedPharmacyIndentsAsync(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return this.BadRequest("The id is invalid.");
            }

            var response = await this.pharmacyRequestService.GetIssuedPharmacyIndentDetailAsync(Convert.ToInt32(id));
            return this.Success(response);
        }

        /// <summary>
        /// The fetch pharmacy indent header.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-indent")]
        public async Task<ActionResult> FetchPharmacyIndentDetailByAdmId([FromBody] PharmacyIndentHeaderModel model)
        {
            model = (PharmacyIndentHeaderModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.FetchPharmacyDetailByAdmId(model.AdmissionId);
            return this.Success(response);
        }

        /// <summary>
        /// Approves the operation theater indent asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("approve-ot-indent")]
        public async Task<ActionResult> ApproveOperationTheaterIndentAsync([FromBody] OTIssueModel model)
        {
            model = (OTIssueModel)EmptyFilter.Handler(model);
            if (model.Products.Count == 0)
            {
                return this.BadRequest("Invalid parameters supplied.");
            }

            var response = await this.pharmacyRequestService.ApproveOTIndents(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the return for indent asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-return-request")]
        public async Task<ActionResult> AddReturnForIndentAsync([FromBody]PharmacyInPatientReturnModel model)
        {
            model = (PharmacyInPatientReturnModel)EmptyFilter.Handler(model);
            var response =await this.pharmacyRequestService.AddIndentReturnAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the return for indent asynchronous.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-return")]
        public async Task<ActionResult> FetchReturnForIndentAsync(int id)
        {
            if(id == 0) { return this.BadRequest("Invalid id passed."); }
            var response= await this.pharmacyRequestService.FetchReturnRequestAsync(id);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches for return inden maint asynchronous.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <param name="approved">if set to <c>true</c> [approved].</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-return-request")]
        public async Task<ActionResult> FetchForReturnIndenMaintAsync(int id, bool approved)
        {
            if (id == 0) { return this.BadRequest("Invalid id passed."); }
            var response = await this.pharmacyRequestService.FetchForReturnIndentAsync(id, approved);
            return this.Success(response);
        }

        /// <summary>
        /// Called when [accept return asynchronous].
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("accept-return")]
        public async Task<ActionResult> OnAcceptReturnAsync([FromBody] PharmacyInPatientReturnModel model)
        {
            model = (PharmacyInPatientReturnModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.OnAcceptReturnAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Called when [reject return asynchronous].
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("reject-return")]
        public async Task<ActionResult> OnRejectReturnAsync([FromBody] PharmacyInPatientReturnModel model)
        {
            model = (PharmacyInPatientReturnModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyRequestService.OnRejectReturnAsync(model);
            return this.Success(response);
        }
    }
}
