using System.Linq;

namespace Hims.Infrastructure.Services
{
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Domain.Entities.Enums;
    using Shared.EntityModels;
    using Shared.UserModels.PharmacyRequest;
    using Shared.UserModels.OperationTheater;
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Threading.Tasks;
    using Hims.Domain.Entities.Pharmacy;

    /// <inheritdoc />
    public class PharmacyRequestServices : IPharmacyRequestService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <inheritdoc cref="IPharmacyRequestService" />
        public PharmacyRequestServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public async Task<int> AddIndentRequest(IndentRequestModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var header = new PharmacyIndentHeader
            {
                AdmissionId = model.AdmissionId,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                DepartmentId = model.DepartmentId,
                IndentDate = DateTime.Now,
                RequiredDate = model.RequiredDate,
                Reason = model.Reason,
                Status = "P",
                LocationId = (int)model.LocationId
            };

            var previousHeaderRecord = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PharmacyIndentHeader>($@"SELECT * FROM ""PharmacyIndentHeader"" where ""CreatedDate""::date = '{header.CreatedDate:yyyy-MM-dd}' and ""AdmissionId"" = {header.AdmissionId}");
            if (previousHeaderRecord == null)
            {
                header.PharmacyIndentHeaderId =
                    await this.unitOfWork.PharmacyIndentHeaders.InsertAsync(header, transaction);
                if (header.PharmacyIndentHeaderId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            else
            {
                header.PharmacyIndentHeaderId = previousHeaderRecord.PharmacyIndentHeaderId;
            }

            var where = " and 1=1";
            if (model.PharmacyProductId != null)
            {
                where += $@" AND ""PharmacyProductId"" = {model.PharmacyProductId}";
            }
            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" AND ""ProductName"" = '{model.ProductName}'";
            }

            var query = $@"SELECT
	                            * 
                            FROM
	                            ""PharmacyIndentDetail"" 
                            WHERE
	                            ""PharmacyIndentHeaderId"" = {header.PharmacyIndentHeaderId} 
	                            {where}	                            
	                            AND ""Status"" != 'A'
	                            AND ""Status"" != 'R'";
            var detailPreviousRecord = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PharmacyIndentDetail>(query);

            if (detailPreviousRecord == null)
            {
                var detail = new PharmacyIndentDetail
                {
                    PharmacyIndentHeaderId = header.PharmacyIndentHeaderId,
                    PharmacyProductId = model.PharmacyProductId,
                    Quantity = model.Quantity,
                    Status = "P",
                    ProductName = model.ProductName,
                    RequestedDate = DateTime.Now
                };
                detail.PharmacyIndentDetailId =
                    await this.unitOfWork.PharmacyIndentDetails.InsertAsync(detail, transaction);
                if (detail.PharmacyIndentDetailId == 0)
                {
                    transaction.Rollback();
                    return -2;
                }
            }
            else
            {
                detailPreviousRecord.Quantity += model.Quantity;
                detailPreviousRecord.CreatedBy = model.CreatedBy;
                detailPreviousRecord.CreatedDate = DateTime.Now;
                var updateResponse = await this.unitOfWork.PharmacyIndentDetails.UpdateAsync(detailPreviousRecord, transaction);
                if (updateResponse <= 0)
                {
                    transaction.Rollback();
                    return -3;
                }
            }

            transaction.Commit();
            return header.PharmacyIndentHeaderId;
        }

        /// <inheritdoc />
        public async Task<int> RejectPharmacyProductIndent(int indentHeaderId, int indentDetailId, int loginAccId)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var pharmacyIndentDetailRecord = await this.unitOfWork.PharmacyIndentDetails.FindAsync(m => m.PharmacyIndentDetailId == indentDetailId && m.PharmacyIndentHeaderId == indentHeaderId);
            pharmacyIndentDetailRecord.Status = "R";
            pharmacyIndentDetailRecord.CreatedBy = loginAccId;
            pharmacyIndentDetailRecord.CreatedDate = DateTime.Now;
            var detailResponse = await this.unitOfWork.PharmacyIndentDetails.UpdateAsync(pharmacyIndentDetailRecord, transaction);

            if (detailResponse <= 0)
            {
                transaction.Rollback();
                return -1;
            }

            transaction.Commit();
            return detailResponse;
        }

        /// <inheritdoc />
        public async Task<int> CancelIndentRequest(int indentHeaderId, int indentDetailId)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var detailQuery = $@"DELETE FROM ""PharmacyIndentDetail"" WHERE ""PharmacyIndentHeaderId"" = {indentHeaderId} and ""PharmacyIndentDetailId"" = {indentDetailId}";
            var detailResponse = await this.unitOfWork.Current.ExecuteAsync(detailQuery, transaction);
            if (detailResponse <= 0)
            {
                transaction.Rollback();
                return -1;
            }

            transaction.Commit();
            return detailResponse;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIndentHeaderModel>> FetchPharmacyHeader(PharmacyIndentHeaderModel model)
        {
            var where = "where 1 = 1";
            if (model.RequestDate != null)
            {
                where += $@" and PIH.""CreatedDate""::date = '{model.RequestDate?.ToString("yyyy-MM-dd")}'";
            }

            if (model.PharmacyIndentHeaderId > 0)
            {
                where += $@" and PIH.""PharmacyIndentHeaderId"" = {model.PharmacyIndentHeaderId}";
            }

            if (model.AdmissionId > 0)
            {
                where += $@" and PIH.""AdmissionId"" = {model.AdmissionId}";
            }

            if (model.LocationId != null)
            {
                where += $@" and PIH.""LocationId"" = {model.LocationId}";
            }

            var query =
                $@"SELECT count(PIH.*) over () as ""TotalItems"",PIH.""PharmacyIndentHeaderId"",
                                                                PIH.""IndentDate"", 
                                                                PIH.""DepartmentId"",
                                                                D.""DepartmentName"",
                                                                PIH.""RequiredDate"",
                                                                PIH.""Reason"",
                                                                PIH.""AdmissionId"",
                                                                PIH.""ApprovedBy"", PIH.""ApprovedDate"",
                                                                AA.""FullName"" as ""ApprovedByName"",
                                                                PIH.""CreatedBy"", PIH.""CreatedDate"",PIH.""Status"",
                                                                A.""FullName"" as ""CreatedByName""
	                                    FROM ""PharmacyIndentHeader"" PIH	
	                                    join ""Account"" A on A.""AccountId"" = PIH.""CreatedBy""
	                                    left join ""Account"" AA on AA.""AccountId"" = PIH.""ApprovedBy""
	                                    left join ""Department"" D on D.""DepartmentId"" = PIH.""DepartmentId""
	                                    {where}
	                                    Order by PIH.""CreatedDate"" desc";
            //model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
            //query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";

            var result = await this.unitOfWork.Current.QueryAsync<PharmacyIndentHeaderModel>(query);

            foreach (var item in result)
            {
                var indentDetails = await this.unitOfWork.PharmacyIndentDetails.FindAllAsync(m => m.PharmacyIndentHeaderId == item.PharmacyIndentHeaderId && m.Status == "R");
                item.IsRejectedProductsExists = indentDetails.Count() > 0;
            }

            return result;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIndentDetailModel>> FetchPharmacyDetail(int pharmacyIndentHeaderId)
        {
            var query =
                $@"SELECT distinct PID.""PharmacyIndentDetailId"", PID.""PharmacyIndentHeaderId"", PID.""PharmacyProductId"", PID.""Quantity"", 
	                PID.""Status"",COALESCE (PP.""ProductName"",PID.""ProductName"") as ""ProductName"",PIH.""PharmacyIssueHeaderId"",
	                case when PIH.""PharmacyIssueHeaderId"" is not null and PID.""Status"" = 'A'
					then (Select RP.""RetailName"" from ""PharmacyIssueDetail"" PID 
	                 join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = PID.""RetailStockId""
	                 join ""RetailWareHouseLink"" RWL on RWL.""RetailWareHouseLinkId"" = PRS.""RetailWareHouseLinkId""
					 join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = RWL.""RetailPharmacyId""
	                 where PID.""PharmacyIssueHeaderId"" = PIH.""PharmacyIssueHeaderId""
	                 and PID.""PharmacyProductId"" = PID.""PharmacyProductId"" limit 1) end as ""RetailName""
	                                   --,PIHD.""Quantity"" as ""ApprovedQuantity""
                                           , PID.""CreatedDate"",A.""FullName"" as ""CreatedByName""
									   FROM ""PharmacyIndentDetail"" PID 
	                                    left join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PID.""PharmacyProductId""
										left join ""PharmacyIssueHeader"" PIH on PIH.""PharmacyIndentHeaderId"" = PID.""PharmacyIndentHeaderId""
										--left join ""PharmacyIssueDetail"" PIHD on PIHD.""PharmacyIssueHeaderId"" = PIH.""PharmacyIssueHeaderId""
										--and PIHD.""PharmacyProductId"" = PID.""PharmacyProductId""
                                        left join ""Account"" A on A.""AccountId""=PID.""CreatedBy""
                                        where PID.""PharmacyIndentHeaderId"" = {pharmacyIndentHeaderId} order by PID.""PharmacyIndentDetailId"" desc	";
            return await this.unitOfWork.Current.QueryAsync<PharmacyIndentDetailModel>(query);
        }


        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIndentHeaderModel>> FetchAllPendingIndent(PharmacyIndentHeaderModel model)
        {
            var where = "where 1 = 1";
            //if (model.RequestDate != null)
            //{
            //    where += $@" and PIH.""CreatedDate""::date = '{model.RequestDate?.ToString("yyyy-MM-dd")}'";
            //}
            if (model.FromDate != null)
            {
                where += $@" and  PIH.""CreatedDate""::date  >= '{model.FromDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.ToDate != null)
            {
                where += $@" and  PIH.""CreatedDate""::date  <= '{model.ToDate?.ToString("yyyy-MM-dd")}' ";
            }
            if (model.PatientId != null)
            {
                where += $@" and P.""PatientId"" = '{model.PatientId}'";
            }
            if (model.UMRNo != null)
            {
                where += $@" and  P.""UMRNo"" ilike '%{model.UMRNo}%'";
            }
            if (model.Mobile != null)
            {
                where += $@" and  P.""Mobile"" ilike '%{model.Mobile}%'";
            }
            if (model.ProviderId != null)
            {
                where += $@" and  Pr.""ProviderId"" = '{model.ProviderId}'";
            }
            if (model.ApprovedBy != null)
            {
                where += $@" and  PIH.""ApprovedBy"" = '{model.ApprovedBy}'";
            }
            if (model.RequestedBy != null)
            {
                where += $@" and  PIH.""CreatedBy"" = '{model.RequestedBy}'";
            }

            if (model.LocationId != null)
            {
                where += $@" and PIH.""LocationId"" = {model.LocationId}";
            }

            var query =
                $@"SELECT distinct PIH.""PharmacyIndentHeaderId"",count(PIH.*) over () as ""TotalItems"",P.""FullName"" AS ""PatientName"",P.""Age"",
                                    P.""Mobile"",P.""Gender"",P.""UMRNo"",Pr.""ProviderId"",Pr.""FullName"",PIH.""IndentDate"", PIH.""DepartmentId"",
                                    D.""DepartmentName"", PIH.""RequiredDate"", PIH.""Reason"", PIH.""AdmissionId"", PIH.""ApprovedBy"",PIH.""ApprovedDate"",
                                    AA.""FullName"" as ""ApprovedByName"", AAR.""RoleName"" as ""ApprovedByRoleName"",
                                    PIH.""CreatedBy"", PIH.""CreatedDate"",PIH.""Status"",
                                     A.""FullName"" as ""CreatedByName"", AR.""RoleName"" as ""CreatedByRoleName"",
                                        count(PID.*) over() as ""NumRequestedItems"",
                                        CASE WHEN 'P' = any(array_agg(PID.""Status"") OVER(partition by PIH.""PharmacyIndentHeaderId"" )::text[])  then 2  else 1 end  ""IndentStatusTypeId"",
                                        CASE WHEN rr.""ReceiptId"" IS NOT NULL then TRUE  else FALSE end  ""IsReceiptGenerated"",
                                        rr.""ReceiptId""

                                        FROM ""PharmacyIndentHeader"" PIH	
										join ""Admission"" Ad on Ad.""AdmissionId"" = PIH.""AdmissionId""
										join ""Patient"" P on P.""PatientId"" = Ad.""PatientId""
	                                    join ""Account"" A on A.""AccountId"" = PIH.""CreatedBy""
	                                    left join ""Account"" AA on AA.""AccountId"" = PIH.""ApprovedBy""
                                        left join ""Role"" AR on A.""RoleId""= AR.""RoleId""
                                        left join ""Role"" AAR on AA.""RoleId"" = AAR.""RoleId""
                                        left join ""Department"" D on D.""DepartmentId"" = PIH.""DepartmentId""
										left join ""Provider"" Pr on Pr.""ProviderId"" = Ad.""ProviderId""
										left join ""Receipt"" rr on (rr.""ReceiptAreaMainId"" = PIH.""PharmacyIndentHeaderId"" AND rr.""ReceiptAreaTypeId"" = {(int)ReceiptAreaType.Pharmacy})

                                        join ""PharmacyIndentDetail"" PID on PID.""PharmacyIndentHeaderId"" = PIH.""PharmacyIndentHeaderId""
	                                    {where}
	                                    Order by PIH.""CreatedDate"" desc";

            return await this.unitOfWork.Current.QueryAsync<PharmacyIndentHeaderModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> IssueIndentBillAsync(PharmacyIssueRequest model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var header = new PharmacyIssueHeader
                {
                    PharmacyIssueHeaderId = model.PharmacyIssueHeaderId,
                    PharmacyIndentHeaderId = model.PharmacyIndentHeaderId == 0 ? (int?)null : model.PharmacyIndentHeaderId,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    OverallDiscount = model.Discount != null ? Math.Round((double)model.Discount, 2) : model.Discount,
                    OverallGst = Math.Round(model.TaxAmount, 2),
                    OverallNetAmount = Math.Round(model.NetAmount, 2),
                    OverallTotal = Math.Round(model.Total, 2)
                };

                header.PharmacyIssueHeaderId = await this.InsertIssueHeaderAsync(header, transaction);
                if (header.PharmacyIssueHeaderId <= 0)
                {
                    transaction.Rollback();
                    return -1;
                }

                var detail = new PharmacyIssueDetail
                {
                    PharmacyIssueHeaderId = header.PharmacyIssueHeaderId,
                    NetAmount = Math.Round(model.NetAmount, 2),
                    DiscountAmount = model.Discount != null ? Math.Round((double)model.Discount, 2) : model.Discount,
                    DiscountPercentage = model.DiscountPerItem,
                    GstAmount = Math.Round(model.TaxAmount, 2),
                    GstPercentage = Math.Round(model.GstPercentage, 2),
                    PharmacyProductId = model.PharmacyProductId,
                    RetailStockId = model.PharmacyRetailStockId,
                    Quantity = model.Quantity,
                    Total = Math.Round(model.Total, 2),
                    PharmacyIndentDetailId = model.PharmacyIndentDetailId
                };

                detail.PharmacyIssueDetailId = await this.unitOfWork.PharmacyIssueDetails.InsertAsync(detail, transaction);
                if (detail.PharmacyIssueDetailId == 0)
                {
                    transaction.Rollback();
                    return -2;
                }

                var completeIndents = (await this.unitOfWork.PharmacyIndentDetails.FindAllAsync(
                                       m => m.PharmacyIndentHeaderId == model.PharmacyIndentHeaderId)).ToList();
                if (completeIndents.Count > 0)
                {
                    var indentDetail = completeIndents.Find(m => m.PharmacyIndentDetailId == model.PharmacyIndentDetailId);
                    if (indentDetail != null)
                    {
                        indentDetail.Status = "A";
                        indentDetail.CreatedBy = model.LoginAccountId;
                        indentDetail.CreatedDate = DateTime.Now;
                        indentDetail.PharmacyProductId = detail.PharmacyProductId;
                        var detailResponse = await this.unitOfWork.PharmacyIndentDetails.UpdateAsync(indentDetail, transaction);
                        if (detailResponse <= 0)
                        {
                            transaction.Rollback();
                            return -3;
                        }
                    }
                }


                var indentHeader = await this.unitOfWork.PharmacyIndentHeaders.FindAsync(
                                       m => m.PharmacyIndentHeaderId == model.PharmacyIndentHeaderId);
                if (indentHeader != null)
                {
                    var allIndentDetails = await this.unitOfWork.PharmacyIndentDetails.FindAllAsync(m => m.PharmacyIndentHeaderId == indentHeader.PharmacyIndentHeaderId);
                    var allIndentDetailList = allIndentDetails.ToList();
                    if (allIndentDetailList.Count > 0)
                    {
                        var findValue = allIndentDetailList.Any(m => m.Status == "P");
                        if (!findValue)
                        {
                            indentHeader.Status = "A";
                        }
                    }

                    indentHeader.IndentDate = DateTime.Now;
                    indentHeader.ModifiedBy = model.CreatedBy;
                    indentHeader.ModifiedDate = DateTime.Now;
                    indentHeader.ApprovedBy = model.CreatedBy;
                    indentHeader.ApprovedDate = DateTime.Now;
                    var headerResponse = await this.unitOfWork.PharmacyIndentHeaders.UpdateAsync(indentHeader, transaction);
                    if (headerResponse <= 0)
                    {
                        transaction.Rollback();
                        return -4;
                    }
                }



                var retailStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);

                if (retailStock != null)
                {
                    retailStock.QuantityOut += model.Quantity;
                    retailStock.ModifiedBy = model.CreatedBy;
                    retailStock.ModifiedDate = DateTime.Now;
                    var retailResponse = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(retailStock, transaction);
                    if (retailResponse <= 0)
                    {
                        transaction.Rollback();
                        return -5;
                    }
                }
                else
                {
                    transaction.Rollback();
                    return -6;
                }

                transaction.Commit();

                await this.CheckIPIndentStatus(model.PharmacyIndentHeaderId);

                return header.PharmacyIssueHeaderId;
            }
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIssueDisplayModel>> GetIssuedPharmacyIndentDetailAsync(int pharmacyIssueHeaderId)
        {
            var query = $@"SELECT PIH.""PharmacyIssueHeaderId"", PIH.""PharmacyIndentHeaderId"", PIH.""OverallNetAmount"", PIH.""OverallGst"", PIH.""OverallDiscount"", 
                                PIH.""CreatedBy"", PIH.""CreatedDate"",PID.""PharmacyIssueDetailId"", PID.""PharmacyIssueHeaderId"", PID.""PharmacyProductId"", PID.""RetailStockId"",
                                PID.""GstPercentage"", PID.""DiscountPercentage"", PID.""NetAmount"", PID.""GstAmount"", PID.""DiscountAmount"", PID.""Quantity"",
                                PD.""ProductName"",PRS.""ExpiryDate"",PIH.""OverallTotal"",PID.""Total"",RP.""RetailName"" 
                                    FROM ""PharmacyIssueHeader"" PIH 
	                                join ""PharmacyIssueDetail"" PID on  PID.""PharmacyIssueHeaderId""= PIH.""PharmacyIssueHeaderId""
	                                join ""PharmacyProduct"" PD on PD.""PharmacyProductId"" = PID.""PharmacyProductId""
	                                join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = PID.""RetailStockId""
									join ""RetailWareHouseLink"" PWL on PWL.""RetailWareHouseLinkId"" = PRS.""RetailWareHouseLinkId""
									join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = PWL.""RetailPharmacyId""
                                    where PIH.""PharmacyIssueHeaderId"" = {pharmacyIssueHeaderId}";

            return await this.unitOfWork.Current.QueryAsync<PharmacyIssueDisplayModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIssueDisplayModel>> GetIssuedPharmacyIndentDetailAltAsync(int id)
        {
            var query = $@"SELECT
	                        PIH.""OverallNetAmount"",
	                        PIH.""OverallGst"",
	                        PIH.""OverallDiscount"",
	                        PID.""GstPercentage"",
	                        PID.""DiscountPercentage"",
	                        PID.""NetAmount"",
	                        PID.""GstAmount"",
	                        PID.""DiscountAmount"",
	                        PID.""Quantity"",
	                        PD.""ProductName"",
	                        PIH.""OverallTotal"",
	                        PID.""Total"",
                            PRS.""Mrp""
                        FROM
	                        ""PharmacyIssueHeader"" PIH
	                        JOIN ""PharmacyIssueDetail"" PID ON PID.""PharmacyIssueHeaderId"" = PIH.""PharmacyIssueHeaderId""
	                        JOIN ""PharmacyProduct"" PD ON PD.""PharmacyProductId"" = PID.""PharmacyProductId""
                            JOIN ""PharmacyRetailStock"" PRS ON PRS.""PharmacyRetailStockId"" = PID.""RetailStockId""
                        WHERE
                            PIH.""PharmacyIndentHeaderId"" = {id}";

            return await this.unitOfWork.Current.QueryAsync<PharmacyIssueDisplayModel>(query);
        }

        /// <inheritdoc />
        public async Task<string> FindProductByPharmacyProduct(int pharmacyProductId)
        {
            var query = $@"SELECT ""ProductName"" FROM ""PharmacyProduct""  WHERE ""PharmacyProductId"" = (SELECT ""PharmacyProductId"" FROM ""PharmacyProduct""  WHERE ""PharmacyProductId"" = {pharmacyProductId})";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        /// <summary>
        /// The check ip indent status.
        /// </summary>
        /// <param name="ipIndentId">
        /// The ip indent id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        private async Task<int> CheckIPIndentStatus(int ipIndentId)
        {
            var indentHeader = await this.unitOfWork.PharmacyIndentHeaders.FindAsync(m => m.PharmacyIndentHeaderId == ipIndentId);
            if (indentHeader != null)
            {
                var allIndentDetails = await this.unitOfWork.PharmacyIndentDetails.FindAllAsync(m => m.PharmacyIndentHeaderId == indentHeader.PharmacyIndentHeaderId);
                var allIndentDetailList = allIndentDetails.ToList();
                if (allIndentDetailList.Count > 0)
                {
                    var findValue = allIndentDetailList.Any(m => m.Status == "P");
                    if (!findValue)
                    {
                        indentHeader.Status = "A";
                        var headerResponse = await this.unitOfWork.PharmacyIndentHeaders.UpdateAsync(indentHeader);
                    }
                    else
                    {
                        return 0;
                    }
                }
            }
            return 0;
        }

        /// <summary>
        /// The insert issue header async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="transaction">
        /// The transaction.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<int> InsertIssueHeaderAsync(PharmacyIssueHeader model, IDbTransaction transaction)
        {
            if (model.PharmacyIssueHeaderId > 0)
            {
                var header = await this.unitOfWork.PharmacyIssueHeaders.FindAsync(
                                 m => m.PharmacyIssueHeaderId == model.PharmacyIssueHeaderId);
                header.OverallGst += model.OverallGst;
                header.OverallDiscount += model.OverallDiscount;
                header.OverallNetAmount += model.OverallNetAmount;
                header.OverallTotal += model.OverallTotal;
                header.ModifiedBy = model.CreatedBy;
                header.ModifiedDate = DateTime.Now;
                var response = await this.unitOfWork.PharmacyIssueHeaders.UpdateAsync(header, transaction);
                if (response > 0)
                {
                    return header.PharmacyIssueHeaderId;
                }
                else
                {
                    return -1;
                }
            }
            else
            {
                return await this.unitOfWork.PharmacyIssueHeaders.InsertAsync(model, transaction);
            }
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyIndentHeaderModel>> FetchPharmacyDetailByAdmId(int admissionId)
        {
            var where = "where 1 = 1";

            if (admissionId > 0)
            {
                where += $@" and PIH.""AdmissionId"" = {admissionId}";
            }

            var query =
                $@"with main as (SELECT distinct PIH.""PharmacyIndentHeaderId"", PIH.""RequiredDate"",PID.""CreatedDate"" as ""IndentOn"", 
				PID. ""PharmacyIndentDetailId"" , PIH.""CreatedBy"", PIH.""CreatedDate"", A.""FullName"" as ""CreatedByName"" ,  
				AR.""RoleName"" as ""CreatedByRoleName"",PID.""Status"" ,PID.""Quantity"",PISD.""Quantity"" as ""IssueQuantity"",RP.""RetailName"",
				COALESCE(PP.""ProductName"", PID.""ProductName"") as ""IssueProductName"",PP.""GenericName"",PID.""RequestedDate"",PISD.""PharmacyIssueDetailId""
				,sum(pir.""ReturnQuantity"") as ""ReturnQuantity""
                                        FROM ""PharmacyIndentHeader"" PIH
                                        join ""Account"" A on A.""AccountId"" = PIH.""CreatedBy""
                                        join ""PharmacyIndentDetail"" PID on PID.""PharmacyIndentHeaderId"" = PIH.""PharmacyIndentHeaderId""
                                        left join ""Role"" AR on AR.""RoleId"" = A.""RoleId""
                                        left join ""PharmacyIssueHeader"" PISH on PISH.""PharmacyIndentHeaderId"" = PID.""PharmacyIndentHeaderId""
                                        left join ""PharmacyIssueDetail"" PISD on PISD.""PharmacyIssueHeaderId"" = PISH.""PharmacyIssueHeaderId"" and PISD.""PharmacyIndentDetailId"" = PID.""PharmacyIndentDetailId"" 
                                        left join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = PISD.""RetailStockId""
                                        left join ""RetailWareHouseLink"" RWL on RWL.""RetailWareHouseLinkId"" = PRS.""RetailWareHouseLinkId""
									    left join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = RWL.""RetailPharmacyId""
                                        left join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PID.""PharmacyProductId""
                                        left join public.""PharmacyInPatientReturn"" pir on pir.""PharmacyIssueDetailId"" = PISD.""PharmacyIssueDetailId"" 
                                        {where}                                    
                                        group by PIH.""PharmacyIndentHeaderId"", PIH.""RequiredDate"",PID.""CreatedDate"", 
				PID. ""PharmacyIndentDetailId"" , PIH.""CreatedBy"", PIH.""CreatedDate"", A.""FullName""  ,  
				AR.""RoleName"" ,PID.""Status"" ,PID.""Quantity"",PISD.""Quantity"" ,RP.""RetailName"",
				PP.""ProductName"", PID.""ProductName"",PP.""GenericName"",PID.""RequestedDate"",PISD.""PharmacyIssueDetailId""
				 Order by PIH.""CreatedDate"" desc)
										select count(*) over () as ""TotalItems"",* from main";


            var result = await this.unitOfWork.Current.QueryAsync<PharmacyIndentHeaderModel>(query);
            return result;
        }

        /// <inheritdoc />
        public async Task<int> AddIndentReturnAsync(PharmacyInPatientReturnModel model)
        {
            var mod = new PharmacyInPatientReturn
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                PharmacyIssueDetailId = model.PharmacyIssueDetailId,
                ReturnQuantity = model.ReturnQuantity
            };

            return await this.unitOfWork.PharmacyInPatientReturns.InsertAsync(mod);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyInPatientReturnModel>> FetchReturnRequestAsync(int pharmacyIssueDetailId)
        {
            var query = $@"select pipr.""PharmacyInPatientReturnId"" ,pipr.""PharmacyIssueDetailId"" ,pipr.""ReturnQuantity"" ,pipr.""CreatedBy"" ,pipr.""CreatedDate"" ,
		                            pipr.""AcceptedBy"" ,pipr.""AcceptedDate"" , a.""FullName"" as ""CreatedByName"", a2.""FullName"" as ""AcceptedByName""
	                            from public.""PharmacyInPatientReturn"" pipr 
	                            join ""Account"" a on a.""AccountId"" = pipr.""CreatedBy"" 
	                            left join ""Account"" a2 on a2.""AccountId"" = pipr.""AcceptedBy"" 
	                            where pipr.""PharmacyIssueDetailId"" = {pharmacyIssueDetailId}";
            return await this.unitOfWork.Current.QueryAsync<PharmacyInPatientReturnModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PharmacyInPatientReturnModel>> FetchForReturnIndentAsync(int retialPharmacyId, bool approved)
        {
            var where = $@" where rwhl.""RetailPharmacyId"" = {retialPharmacyId}";
            if (approved)
            {
                where += $@" and pipr.""AcceptedBy"" is null";
            }

            var query = $@"select pipr.""PharmacyInPatientReturnId"" ,pipr.""PharmacyIssueDetailId"" ,pipr.""ReturnQuantity"" ,pipr.""CreatedBy"" ,pipr.""CreatedDate"" ,
		                            pipr.""AcceptedBy"" ,pipr.""AcceptedDate"" , a.""FullName"" as ""CreatedByName"", a2.""FullName"" as ""AcceptedByName"",
		                            pid.""PharmacyProductId"" , pid.""RetailStockId"" , pp.""ProductName"" ,pp.""GenericName"" ,
		                            p.""FullName"" as ""PatientName"", p.""Mobile"",p.""UMRNo"" 
	                            from public.""PharmacyInPatientReturn"" pipr 
	                            join ""Account"" a on a.""AccountId"" = pipr.""CreatedBy"" 
	                            left join ""Account"" a2 on a2.""AccountId"" = pipr.""AcceptedBy"" 
	                            join public.""PharmacyIssueDetail"" pid on pid.""PharmacyIssueDetailId"" = pipr.""PharmacyIssueDetailId"" 
	                            join public.""PharmacyProduct"" pp on pp.""PharmacyProductId"" = pid.""PharmacyProductId"" 
	                            join public.""PharmacyIssueHeader"" pih on pih.""PharmacyIssueHeaderId"" = pid.""PharmacyIssueHeaderId"" 
	                            join public.""PharmacyIndentHeader"" pih2 on pih2.""PharmacyIndentHeaderId"" = pih.""PharmacyIndentHeaderId"" 
	                            join public.""Admission"" ad on ad.""AdmissionId"" = pih2.""AdmissionId"" 
	                            join public.""Patient"" p on p.""PatientId"" = ad.""PatientId""
	                            join public.""PharmacyRetailStock"" prs on prs.""PharmacyRetailStockId"" = pid.""RetailStockId"" 
	                            join public.""RetailWareHouseLink"" rwhl on rwhl.""RetailWareHouseLinkId"" = prs.""RetailWareHouseLinkId"" 
	                            {where}
	                            order by pipr.""CreatedDate"" desc";

            return await this.unitOfWork.Current.QueryAsync<PharmacyInPatientReturnModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> OnAcceptReturnAsync(PharmacyInPatientReturnModel model)
        {
            var findOld = await this.unitOfWork.PharmacyInPatientReturns.FindAsync(h => h.PharmacyInPatientReturnId == model.PharmacyInPatientReturnId);
            if (findOld == null)
            {
                return -1;
            }

            findOld.AcceptedBy = model.CreatedBy;
            findOld.AcceptedDate = DateTime.UtcNow.AddMinutes(330);

            var findStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(s => s.PharmacyRetailStockId == model.RetailStockId);
            if (findStock == null)
            {
                return -1;
            }
            findStock.QuantityOut -= findOld.ReturnQuantity;
            findStock.ModifiedBy = model.CreatedBy;
            findStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(findStock);

            return await this.unitOfWork.PharmacyInPatientReturns.UpdateAsync(findOld);
        }

        /// <inheritdoc />
        public async Task<int> OnRejectReturnAsync(PharmacyInPatientReturnModel model)
        {
            var query = $@"DELETE FROM public.""PharmacyInPatientReturn"" WHERE ""PharmacyInPatientReturnId"" = {model.PharmacyInPatientReturnId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }


        /// <inheritdoc />
        public async Task<int> ApproveOTIndents(OTIssueModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();

            int returnFunction()
            {
                transaction.Rollback();
                return -1;
            }

            var header = new PharmacyIssueHeader
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                OverallGst = 0,
                OverallNetAmount = 0,
                OverallTotal = 0,
                OperationIndentHeaderId = model.OperationIndentHeaderId
            };

            header.PharmacyIssueHeaderId = await this.unitOfWork.PharmacyIssueHeaders.InsertAsync(header, transaction);

            if (header.PharmacyIssueHeaderId <= 0)
            {
                returnFunction();
            }

            foreach (var product in model.Products)
            {
                var getRetailStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(s => s.PharmacyRetailStockId == (int)product.PharmacyRetailStockId);
                if (getRetailStock == null)
                {
                    returnFunction();
                }

                var issueDetail = new PharmacyIssueDetail
                {
                    DiscountAmount = null,
                    DiscountPercentage = null,
                    GstAmount = 0,
                    GstPercentage = 0,
                    NetAmount = 0,
                    PharmacyIssueHeaderId = header.PharmacyIssueHeaderId,
                    PharmacyProductId = product.PharmacyProductId,
                    Quantity = product.Quantity,
                    RetailStockId = (int)product.PharmacyRetailStockId,
                    Total = 0
                };

                issueDetail.PharmacyIssueDetailId = await this.unitOfWork.PharmacyIssueDetails.InsertAsync(issueDetail, transaction);

                if (issueDetail.PharmacyIssueDetailId <= 0)
                {
                    transaction.Rollback();
                    return -1;
                }

                getRetailStock.QuantityOut += product.Quantity;
                getRetailStock.ModifiedBy = model.CreatedBy;
                getRetailStock.ModifiedDate = DateTime.Now;

                var updateRetailStockResponse = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(getRetailStock, transaction);

                if (updateRetailStockResponse == 0)
                {
                    returnFunction();
                }

                var otStock = new OperationStock
                {
                    Barcode = getRetailStock.Barcode,
                    BatchNumber = getRetailStock.BatchNumber,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    ExpiryDate = getRetailStock.ExpiryDate,
                    Mrp = getRetailStock.Mrp,
                    PharmacyProductId = getRetailStock.PharmacyProductId,
                    PurchaseRate = getRetailStock.PurchaseRate,
                    QuantityIn = product.Quantity,
                    QuantityOut = 0,
                    PharmacyRetailStockId = getRetailStock.PharmacyRetailStockId
                };

                var getOldOTStock = await this.unitOfWork.OperationStocks.FindAsync(o => o.PharmacyStockId == getRetailStock.PharmacyStockId);
                if (getOldOTStock == null)
                {
                    otStock.OperationStockId = await this.unitOfWork.OperationStocks.InsertAsync(otStock, transaction);
                    if (otStock.OperationStockId == 0)
                    {
                        returnFunction();
                    }
                }
                else
                {
                    getOldOTStock.QuantityIn += product.Quantity;
                    getOldOTStock.ModifiedBy = model.CreatedBy;
                    getOldOTStock.ModifiedDate = DateTime.Now;

                    var otUpdateResponse = await this.unitOfWork.OperationStocks.UpdateAsync(getOldOTStock, transaction);
                    if (otUpdateResponse == 0)
                    {
                        returnFunction();
                    }
                }

                var getOTIndentProducts = await this.unitOfWork.OperationIndentDetails.FindAsync(x => x.OperationIndentHeaderId == model.OperationIndentHeaderId && x.PharmacyProductId == product.PharmacyProductId);
                if (getOTIndentProducts == null)
                {
                    returnFunction();
                }
                getOTIndentProducts.Status = "A";
                var indentProductUpdateResponse = await this.unitOfWork.OperationIndentDetails.UpdateAsync(getOTIndentProducts, transaction);
                if (indentProductUpdateResponse == 0)
                {
                    returnFunction();
                }
            }

            transaction.Commit();

            await this.CheckOTIndentStatus(model.OperationIndentHeaderId, model.CreatedBy);

            return header.PharmacyIssueHeaderId;
        }

        /// <summary>
        /// Checks the ot indent status.
        /// </summary>
        /// <param name="otIndentHeaderId">The ot indent header identifier.</param>
        private async Task CheckOTIndentStatus(int otIndentHeaderId, int approvedBy)
        {
            var header = await this.unitOfWork.OperationIndentHeaders.FindAsync(h => h.OperationIndentHeaderId == otIndentHeaderId);
            if (header != null)
            {
                var details = (await this.unitOfWork.OperationIndentDetails.FindAllAsync(d => d.OperationIndentHeaderId == header.OperationIndentHeaderId && d.Status == "P")).ToList();
                if (details.Count > 0)
                {
                    header.Status = "PA";
                }
                else
                {
                    header.Status = "A";
                }
                header.ApprovedBy = approvedBy;
                header.ApprovedDate = DateTime.Now;
                await this.unitOfWork.OperationIndentHeaders.UpdateAsync(header);
            }
        }
    }
}