namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using System.Linq;
    using Dapper;
    using Domain.Entities.Vendors;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Shared.Library;
    using Shared.EntityModels;
    using Shared.UserModels.Vendors;
    using Hims.Domain.Entities;
    using Hims.Shared.UserModels.Pharmacy;

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

        /// <inheritdoc cref="IInitialVendorService" />
        public InitialVendorServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc/>
        public async Task<int> InsertProductRequest(List<PharmacyProductRequestModel> model)
        {
            var findStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Pending");
            var findAwaitStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Awaits Approval");
            var insertModel = new List<PharmacyProductRequest>();
            foreach (var product in model)
            {
                var data = new PharmacyProductRequest
                {
                    RaisedBy = product.CreatedBy,
                    RaisedDate = DateTime.Now,
                    PharmacyProductId = (int)product.PharmacyProductId,
                    PharmacyWareHouseId = (int)product.PharmacyWareHouseId,
                    TenderStatusId = !string.IsNullOrEmpty(product.Source) && product.Source == "dashboard" ? findAwaitStatus.TenderStatusId : findStatus.TenderStatusId,
                    RequestedQuantity = product.RequestedQuantity
                };
                insertModel.Add(data);
            }

            return await this.unitOfWork.PharmacyProductRequests.BulkInsertAsync(insertModel);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyProductRequestModel>> FetchRaisedProductsRequest(PharmacyProductRequestModel model)
        {
            var where = "where 1=1";

            if (model.FetchType == "Pending")
            {
                where += $@" and ts.""Status"" = 'Pending' ";
            }

            if (model.FetchType == "Awaits Approval")
            {
                where += $@" and ts.""Status"" = 'Awaits Approval' ";
            }

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

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

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

            var query = $@"select count(ppr.*) over() as ""TotalItems"",pp.""ProductName"" ,pp.""GenericName"" ,pp.""Suppliers"" , pwh.""WareHouseName"",ts.""Status"", a.""FullName"" as ""RaisedByName"",
	                        ppr.""PharmacyProductId"", ppr.""TenderStatusId"", ppr.""RaisedBy"", ppr.""RaisedDate""::date, ppr.""ApprovedBy"", ppr.""ApprovedDate"",
	                        ppr.""PharmacyProductRequestId"", coalesce (l.""Name"", cl.""Name"") as ""LocationName"", ppr.""PharmacyWareHouseId"",
	                        coalesce(ppd.""ROQ"",ppr.""RequestedQuantity"",100) as ""ReorderQuantity"", app.""FullName"" as ""ApprovalGivenByName"", ppr.""ApprovalGivenDate"",pp.""InventoryItem"" 
	                        from vendors.""PharmacyProductRequest"" ppr
	                        join ""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppr.""PharmacyProductId"" 
	                        join ""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = ppr.""PharmacyWareHouseId""
	                        join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = ppr.""TenderStatusId"" 
	                        left join ""Location"" l on l.""LocationId"" = pwh.""LocationId"" 
	                        left join ""Location"" cl on cl.""LocationId"" = pwh.""CentralWarehouseLocationId"" 
	                        left join ""Account"" a ON a.""AccountId"" = ppr.""RaisedBy"" 	
                            left join ""Account"" app ON app.""AccountId"" = ppr.""ApprovalGivenBy"" 	
	                        left join public.""PharmacyProductDetail"" ppd on ppd.""PharmacyWareHouseId"" = ppr.""PharmacyWareHouseId"" and ppd.""PharmacyProductId"" = ppr.""PharmacyProductId""
	                        {where}
	                        order by ppr.""RaisedDate"" desc";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

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

        /// <inheritdoc/>
        public async Task<VendorPurchaseHistory> FetchVendorPurchaseHistoryAsync(PharmacyProductRequestModel model)
        {
            var returnResponse = new VendorPurchaseHistory { FromGrn = new List<VendorPurchaseProductList>(), FromPreferedVendor = new List<VendorPurchaseProductList>() };

            var fromGrnQuery = $@"SELECT ppd.""PharmacyProductId"", ps.""PurchaseRate"", ps.""Mrp"", ppd.""TaxPerItem"", pph.""BillDate"" ,s.""Name"" as ""SupplierName"",
		                                pp.""ProductName"" ,pp.""GenericName"", sale.""Name"" as ""SaleUnitName"",pur.""Name"" as ""PurchaseUnitName"",pp.""SaleUnitQty"" ,pp.""PurchaseUnitQty"" ,pph.""SupplierId""  
		                                FROM ""PharmacyPurchaseDetail"" ppd 
		                                join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppd.""PharmacyPurchaseHeaderId"" 
		                                join ""Supplier"" s on s.""SupplierId"" = pph.""SupplierId"" 
		                                join ""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppd.""PharmacyProductId"" 
		                                join ""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit"" 
		                                join ""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
                                        join ""PharmacyStock"" ps on ps.""PharmacyStockId"" = ppd.""PharmacyStockId"" 
		                                where pp.""PharmacyProductId"" = {model.PharmacyProductId}
		                                order by pph.""BillDate"" desc limit 1";

            var grnQueryResponse = await this.unitOfWork.Current.QueryAsync<VendorPurchaseProductList>(fromGrnQuery);

            returnResponse.FromGrn = grnQueryResponse.ToList();
            var fromPreferedVendorQuery = $@"SELECT sph.""SupplierProductHeaderId"",sp.""PharmacyProductId"", sp.""PurchaseRate"",sp.""Mrp"", pp.""ProductName"" , pp.""GenericName"" ,sale.""Name"" as ""SaleUnitName"",
		                                            pur.""Name"" as ""PurchaseUnitName"",pp.""SaleUnitQty"" ,pp.""PurchaseUnitQty"", tax.""Name"":: int as  ""TaxPerItem"",
                                                    s.""Name"" as ""SupplierName"",sph.""SupplierId"" , s.""DeliverDays"", sp.""SupplierProductDetailId""
	                                            FROM vendors.""SupplierProductDetail"" sp
	                                            join vendors.""SupplierProductHeader"" sph on sph.""SupplierProductHeaderId"" = sp.""SupplierProductHeaderId"" 
                                                join ""Supplier"" s on s.""SupplierId"" = sph.""SupplierId"" 
	                                            join ""PharmacyProduct"" pp ON pp.""PharmacyProductId"" = sp.""PharmacyProductId""
	                                            join ""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit"" 
                                                join ""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
                                                join ""LookupValue"" tax on tax.""LookupValueId"" = pp.""TaxId"" 
                                                where pp.""PharmacyProductId"" = {model.PharmacyProductId} and sp.""PurchaseRate"" is not null
                                                and now()::date  >= sph.""StartDate""::date 
                                                and now()::date  <= sph.""EndDate""::date";
            var preferedVendorResponse = await this.unitOfWork.Current.QueryAsync<VendorPurchaseProductList>(fromPreferedVendorQuery);
            foreach (var vendor in preferedVendorResponse)
            {
                vendor.Formulations = new List<SupplierProductFormulationModel>();
                var formulationQuery = $@"SELECT ""SupplierProductFormulationId"", ""SupplierProductDetailId"", ""Operator"", ""Condition"", ""FOCQuantity""
	                                    FROM vendors.""SupplierProductFormulation""
	                                    where ""SupplierProductDetailId"" = {vendor.SupplierProductDetailId}";
                vendor.Formulations = (await this.unitOfWork.Current.QueryAsync<SupplierProductFormulationModel>(formulationQuery)).ToList();
            }
            returnResponse.FromPreferedVendor = preferedVendorResponse.ToList();
            return returnResponse;
        }

        /// <inheritdoc/>
        public async Task<int> AddProductForApprovalAsync(VendorProductApprovalInsertModel model)
        {
            var listToAdd = new List<PharmacyProductApproval>();
            var tenderId = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Moved To Tender");
            foreach (var prod in model.Vendors)
            {
                foreach (var item in prod.Product)
                {
                    var toBePushed = new PharmacyProductApproval
                    {
                        Mrp = item.PreferedVendor?.Mrp,
                        PurchaseRate = item.PreferedVendor?.PurchaseRate,
                        SupplierId = item.PreferedVendor != null && item.PreferedVendor.SupplierId != null && item.PreferedVendor.SupplierId > 0 ? item.PreferedVendor.SupplierId : null,
                        PharmacyProductId = (int)item.PharmacyProductId,
                        PharmacyProductRequestId = item.PharmacyProductRequestId,
                        PharmacyWareHouseId = (int)item.PharmacyWareHouseId,
                        TenderStatusId = tenderId.TenderStatusId,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Quantity = item.ReorderQuantity,
                        Free = Convert.ToInt32(item.Free)
                    };
                    listToAdd.Add(toBePushed);

                    var getRequest = await this.unitOfWork.PharmacyProductRequests.FindAsync(x => x.PharmacyProductRequestId == item.PharmacyProductRequestId);

                    if (getRequest != null)
                    {
                        getRequest.TenderStatusId = tenderId.TenderStatusId;
                        getRequest.ApprovedDate = DateTime.Now;
                        getRequest.ApprovedBy = model.CreatedBy;

                        await this.unitOfWork.PharmacyProductRequests.UpdateAsync(getRequest);
                    }
                }
            }

            return await this.unitOfWork.PharmacyProductApprovals.BulkInsertAsync(listToAdd);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<VendorProductForApprovalDisplayModel>> FetchPendingForFinalApprovalAsync(VendorProductForApprovalDisplayModel model)
        {
            var where = " where 1=1";
            if (!string.IsNullOrEmpty(model.Status))
            {
                where += $@" and ts.""Status"" = '{model.Status}'";
            }

            var query = $@"SELECT ppa.""PharmacyProductApprovalId"", ppa.""PharmacyProductId"",  ppa.""PurchaseRate"", ppa.""Mrp"", ppa.""SupplierId"", ppa.""TenderStatusId"", ppa.""PharmacyProductRequestId"",
	                                ppa.""CreatedBy"", ppa.""CreatedDate"" as ""ApprovedDate"", ts.""Status"", a.""FullName"" as ""RaisedByName"", ppr.""RaisedDate"" , ap.""FullName"" as ""RequestApprovedBy"",
	                                pp.""ProductName"" ,pp.""GenericName"" , c.""Name"" as ""CompanyName"" ,pwh.""WareHouseName"" ,coalesce (l.""Name"",cl.""Name"") as ""Location"",  s.""Name""  as ""SupplierName"", s.""DeliverDays"",
                                    coalesce (l.""LocationId"",cl.""LocationId"") as ""LocationId"", tax.""Name""::int as ""Tax"", ppa.""Quantity"", ppa.""Free"",ppa.""PharmacyWareHouseId"" , pp.""InventoryItem"", pur.""Name"" as ""PurchaseUnitName""
                                FROM vendors.""PharmacyProductApproval"" ppa
                                join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = ppa.""TenderStatusId"" 
                                join vendors.""PharmacyProductRequest"" ppr on ppr.""PharmacyProductRequestId"" = ppa.""PharmacyProductRequestId"" 
                                join ""Account"" a on a.""AccountId"" = ppr.""RaisedBy"" 
                                join ""Account"" ap on ap.""AccountId""  =  ppa.""CreatedBy""
                                join ""PharmacyProduct"" pp ON pp.""PharmacyProductId"" = ppa.""PharmacyProductId""
                                left join ""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
                                join ""LookupValue"" tax on tax.""LookupValueId"" = pp.""TaxId""
                                join ""Company"" c on c.""CompanyId"" = pp.""CompanyId""                                 
                                join ""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = ppa.""PharmacyWareHouseId"" 
                                left join ""Supplier"" s on s.""SupplierId"" = ppa.""SupplierId"" 
                                left join ""Location"" l on l.""LocationId"" = pwh.""LocationId"" 
                                left join ""Location"" cl on cl.""LocationId"" =pwh.""CentralWarehouseLocationId"" 
                                 {where}
                                order by  ppa.""CreatedDate"" desc ";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<VendorViewModel>> FetchSendedPOAsync(VendorViewModel model)
        {
            var where = "where 1=1";

            if (model.SupplierId > 0)
            {
                where += $@" and s.""UserId"" = {model.SupplierId} and (ts.""Status"" = 'Pending Vendor Acceptance' or ts.""Status"" = 'PartialAccepted')";
            }

            var query = $@"SELECT trsh.""TenderRequestSupplierHeaderId"", trsh.""TenderStatusId"", trsh.""TenderRaisedBy"", trsh.""SupplierId"", trsh.""TenderRaisedDate"", trsh.""IsCompleteAccepted"", trsh.""AcceptedDate"",
		                            trsh.""IsCompleteRejected"", trsh.""CompleteRejectedDate"", trsh.""CompleteRejectionComment"",
		                            s.""Name"" as ""SupplierName"",S.""Address"" ,S.""PinCode"" ,s.""Email"" ,s.""ContactPersonName"" ,s.""Mobile"" ,
		                            a.""FullName"" as ""TenderRaisedByName"", ts.""Status"" 
		                            FROM vendors.""TenderRequestSupplierHeader"" trsh
		                            join ""Supplier"" s on s.""SupplierId"" = trsh.""SupplierId"" 
		                            join ""Account"" a on a.""AccountId"" = trsh.""TenderRaisedBy"" 
		                            join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = trsh.""TenderStatusId"" 		
		                            {where}
		                            order by trsh.""TenderRaisedDate"" desc";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<VendorViewDetailModel>> FetchVendorProductDetailsAsync(VendorViewDetailModel model)
        {
            var where = " where 1=1";
            if (model.TenderRequestSupplierHeaderId != null)
            {
                where += $@" and  trsd.""TenderRequestSupplierHeaderId"" = {model.TenderRequestSupplierHeaderId}";
            }

            var query = $@"SELECT trsd.""TenderRequestSupplierDetailId"", trsd.""TenderRequestSupplierHeaderId"", trsd.""PharmacyProductApprovalId"", trsd.""VendorMrp"", trsd.""VendorPurchaseRate"", trsd.""TenderStatusId"",
		                        trsd.""VendorRejected"", trsd.""VendorRejectedDate"", trsd.""RejectionComment"",
		                        ppa.""PurchaseRate"" , ppa.""Mrp"" , ts.""Status"", pp.""ProductName"" ,pp.""GenericName"" ,pp.""PurchaseUnitQty"" ,pp.""SaleUnitQty"" ,
		                        cate.""Name"" as ""CategoryName"", purc.""Name"" as ""PurchaseUnitName"", sale.""Name"" as ""SaleUnitName""
		                        FROM vendors.""TenderRequestSupplierDetail"" trsd
		                        join vendors.""PharmacyProductApproval"" ppa on ppa.""PharmacyProductApprovalId"" =trsd.""PharmacyProductApprovalId"" 
		                        join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = trsd.""TenderStatusId"" 
		                        join ""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppa.""PharmacyProductId"" 
		                        join ""Company"" c on c.""CompanyId"" = pp.""CompanyId"" 
		                        join ""LookupValue"" cate on cate.""LookupValueId"" = pp.""CategoryId"" 
		                        join ""LookupValue"" purc on purc.""LookupValueId"" = pp.""PurchaseUnit""
		                        join ""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit""
		                        {where}
		                        order by pp.""ProductName"" asc";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<VendorViewDetailModel>> FetchApprovedProductsForVendorAsync(VendorViewDetailModel model)
        {
            var where = " where 1=1 ";
            if (model.SupplierId != null)
            {
                where += $@" and s.""UserId"" = {model.SupplierId}";
            }

            if (!string.IsNullOrEmpty(model.FetchType))
            {
                switch (model.FetchType)
                {
                    case "A":
                        where += $@" and ts.""Status"" = 'VendorAccepted' ";
                        break;
                }
            }

            var query = $@"SELECT trsd.""TenderRequestSupplierDetailId"", trsd.""TenderRequestSupplierHeaderId"", trsd.""PharmacyProductApprovalId"", trsd.""VendorMrp"", trsd.""VendorPurchaseRate"", trsd.""TenderStatusId"", 
	                               trsd.""VendorRejected"", trsd.""VendorRejectedDate"", trsd.""RejectionComment"", trsh.""TenderRaisedDate"" , rb.""FullName"" as ""RaisedByName"",trsh.""AcceptedDate"" ,
	                               s.""Name"" as ""SupplierName"",ppa.""PurchaseRate"" , ppa.""Mrp"", ppa.""PharmacyWareHouseId"", pwh.""WareHouseName"" , coalesce(wl.""Name"", wl2.""Name"") as ""DeliveryLocation"" ,
	                               pp.""ProductName"" ,pp.""GenericName"" ,c.""Name"" as ""CompanyName"", sale.""Name"" as ""SaleUnitName"",purchase.""Name"" as ""PurchaseUnitName"",
	                               coalesce(ppd.""ROQ"", 100) as ""ReorderQuantity"" , ts.""Status"" , pp.""PurchaseUnitQty"" , pp.""SaleUnitQty"" , cat.""Name"" as ""CategoryName""
		                            FROM vendors.""TenderRequestSupplierDetail"" trsd
		                            join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = trsd.""TenderStatusId"" 
		                            join vendors.""TenderRequestSupplierHeader"" trsh on trsh.""TenderRequestSupplierHeaderId"" = trsd.""TenderRequestSupplierHeaderId""  
		                            join public.""Account"" rb on rb.""AccountId"" = trsh.""TenderRaisedBy"" 
		                            join public.""Supplier"" s on s.""SupplierId"" = trsh.""SupplierId"" 
		                            join vendors.""PharmacyProductApproval"" ppa on ppa.""PharmacyProductApprovalId"" = trsd.""PharmacyProductApprovalId""		                           
		                            join public.""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = ppa.""PharmacyWareHouseId"" 
		                            left join public.""Location"" wl on wl.""LocationId"" = pwh.""LocationId"" 
		                            left join public.""Location"" wl2 on wl2.""LocationId"" = pwh.""CentralWarehouseLocationId""
		                            join public.""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppa.""PharmacyProductId"" 
		                            join public.""LookupValue"" cat on cat.""LookupValueId"" = pp.""CategoryId"" 
		                            join public.""Company"" c on c.""CompanyId"" = pp.""CompanyId"" 
		                            join public.""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit"" 
		                            join public.""LookupValue"" purchase on purchase.""LookupValueId"" = pp.""PurchaseUnit""		
		                            left join public.""PharmacyProductDetail"" ppd on ppd.""PharmacyProductId"" = pp.""PharmacyProductId"" and ppd.""PharmacyWareHouseId"" = pwh.""PharmacyWareHouseId"" 
		                             {where}
		                            order by ppa.""CreatedDate"" desc";

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

        /// <inheritdoc/>
        public async Task<int> AddDirectProductAsync(VendorProductForApprovalModel model)
        {
            var insertModel = new List<PharmacyProductRequest>();
            var findStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Pending");
            foreach (var product in model.Product)
            {
                var mainProd = new PharmacyProductRequest()
                {
                    RaisedBy = model.CreatedBy,
                    RaisedDate = DateTime.Now,
                    PharmacyProductId = (int)product.PharmacyProductId,
                    PharmacyWareHouseId = (int)model.PharmacyWareHouseId,
                    TenderStatusId = findStatus.TenderStatusId
                };
                insertModel.Add(mainProd);
            }

            return await this.unitOfWork.PharmacyProductRequests.BulkInsertAsync(insertModel);
        }

        /// <inheritdoc/>
        public async Task<long> RaisePOAsync(VendorProductApprovalInsertModel product)
        {
            var tenderStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "PO Sent");
            using var transaction = this.unitOfWork.BeginTransaction();
            var poHeader = new PurchaseOrderHeader
            {
                CreatedBy = product.CreatedBy,
                CreatedDate = DateTime.Now,
                EstimatedDeliveryDate = product.DeliverDate,
                PharmacyWareHouseId = product.PharmacyWareHouseId,
                PORaiseDate = DateTime.Now,
                SupplierId = product.SupplierId,
                TenderStatusId = tenderStatus.TenderStatusId,
                TotalAmount = product.TotalAmount,
                TotalNetAmount = product.TotalNetAmount,
                TotalTax = product.TotalTax,
                PONumber = await this.GetPoNumber()
            };
            poHeader.PurchaseOrderHeaderId = await this.unitOfWork.PurchaseOrderHeaders.InsertAsync(poHeader, transaction);
            if (poHeader.PurchaseOrderHeaderId == 0)
            {
                transaction.Rollback();
                return -1;
            }

            foreach (var detail in product.Products)
            {
                var poDetail = new PurchaseOrderDetail
                {
                    PurchaseOrderHeaderId = poHeader.PurchaseOrderHeaderId,
                    PharmacyProductApprovalId = detail.PharmacyProductApprovalId,
                    Amount = detail.Amount,
                    NetAmount = detail.NetAmount,
                    Quantity = detail.Quantity,
                    TaxAmount = detail.TaxAmount,
                    IsAddedByGrn = false,
                    Free = detail.Free
                };

                poDetail.PurchaseOrderDetailId = await this.unitOfWork.PurchaseOrderDetails.InsertAsync(poDetail, transaction);
                if (poDetail.PurchaseOrderDetailId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }

                var purchaseApp = await this.unitOfWork.PharmacyProductApprovals.FindAsync(p => p.PharmacyProductApprovalId == poDetail.PharmacyProductApprovalId);
                if (purchaseApp == null)
                {
                    transaction.Rollback();
                    return -1;
                }
                purchaseApp.TenderStatusId = tenderStatus.TenderStatusId;
                var update = await this.unitOfWork.PharmacyProductApprovals.UpdateAsync(purchaseApp, transaction);
                if (update == 0)
                {
                    transaction.Rollback();
                    return -1;
                }

                var findQuotationHeader = await this.unitOfWork.ProductForQuotationHeaders.FindAsync(z => z.ProductForQuotationHeaderId == purchaseApp.ProductForQuotationHeaderId);
                if (findQuotationHeader != null)
                {
                    var statusComp = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Completed");
                    findQuotationHeader.TenderStatusId = statusComp.TenderStatusId;
                    await this.unitOfWork.ProductForQuotationHeaders.UpdateAsync(findQuotationHeader, transaction);
                }
            }

            transaction.Commit();
            return poHeader.PurchaseOrderHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PurchaseOrderHeaderModel>> FetchPurchaseOrderHeaderAsync(PurchaseOrderHeaderModel poHeader)
        {
            var where = " where 1=1";
            if (!string.IsNullOrEmpty(poHeader.PONumber))
            {
                where += $@" and poh.""PONumber"" = '{poHeader.PONumber}'";
            }

            if (poHeader.PurchaseOrderHeaderId > 0)
            {
                where += $@" and  poh.""PurchaseOrderHeaderId"" = {poHeader.PurchaseOrderHeaderId}";
            }

            if (!string.IsNullOrEmpty(poHeader.PurchaseOrderHeaderIds))
            {
                where += $@" and poh.""PurchaseOrderHeaderId"" in ({poHeader.PurchaseOrderHeaderIds})";
            }

            var query = $@"SELECT poh.""PurchaseOrderHeaderId"", poh.""PONumber"", poh.""PORaiseDate"", poh.""EstimatedDeliveryDate"", poh.""CreatedBy"", poh.""CreatedDate"", poh.""TenderStatusId"", poh.""TotalAmount"", poh.""TotalTax"",
		                            poh.""TotalNetAmount"", poh.""SupplierId"", poh.""PharmacyWareHouseId"", s.""Name"" as ""SupplierName"",s.""DueDays"",
		                            pwh.""WareHouseName"" , pwh.""LocationId"" , pwh.""CentralWarehouseLocationId"" ,coalesce (cl.""Name"",wl.""Name"") as ""LocationName"",
		                            c.""FullName"" as ""CreatedByName"", ts.""Status"" 
                                        FROM vendors.""PurchaseOrderHeader"" poh
		                            join public.""Supplier"" s on s.""SupplierId"" = poh.""SupplierId"" 
		                            join public.""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = poh.""PharmacyWareHouseId"" 
		                            left join public.""Location"" cl on cl.""LocationId"" = pwh.""LocationId"" 
		                            left join public.""Location"" wl on wl.""LocationId"" = pwh.""CentralWarehouseLocationId"" 
		                            join public.""Account"" c on c.""AccountId"" = poh.""CreatedBy"" 
		                            join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = poh.""TenderStatusId"" 
		                             {where}
		                            order by poh.""CreatedDate"" desc";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<PurchaseOrderHeaderModel>> FetchOnlyPONumberAsync(string poNumber)
        {
            var where = " and 1=1";
            if (!string.IsNullOrEmpty(poNumber))
            {
                where += $@" and ""PONumber"" ilike '%{poNumber}%'";
            }

            var query = $@"SELECT ""PurchaseOrderHeaderId"", ""PONumber"", ""PORaiseDate"", poh.""CreatedBy"", poh.""CreatedDate"", poh.""TenderStatusId"", ts.""Status"" ,
		                a.""FullName"" as ""CreatedByName""
		                FROM vendors.""PurchaseOrderHeader"" poh
		                join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = poh.""TenderStatusId"" 
		                join public.""Account"" a on a.""AccountId"" = poh.""CreatedBy""
		                where ts.""Status"" != 'Completed' {where} ";
            return await this.unitOfWork.Current.QueryAsync<PurchaseOrderHeaderModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PurchaseOrderDetailModel>> FetchPurchaseOrderDetailAsync(PurchaseOrderDetailModel poDetail)
        {
            var where = " where 1=1";
            if (poDetail.PurchaseOrderHeaderId > 0)
            {
                where += $@" and  pod.""PurchaseOrderHeaderId"" =  {poDetail.PurchaseOrderHeaderId}";
            }

            if (!string.IsNullOrEmpty(poDetail.PurchaseOrderHeaderIds))
            {
                where += $@" and pod.""PurchaseOrderHeaderId"" in ({poDetail.PurchaseOrderHeaderIds})";
            }

            var query = $@"SELECT pod.""PurchaseOrderDetailId"", pod.""PurchaseOrderHeaderId"", pod.""PharmacyProductApprovalId"", pod.""Quantity"",pod.""Free"", pod.""Amount"", pod.""TaxAmount"", pod.""NetAmount"",
		                            ppa.""Mrp"" , ppa.""PurchaseRate"", pp.""ProductName"" , pp.""GenericName"" ,pp.""IsGeneralItem"" , pp.""CompanyId"" , pp.""CategoryId"" ,cat.""Name"" as ""CategoryName"",
		                            pp.""TaxId"" ,tax.""Name""::int as ""Tax"", c.""Name"" as ""CompanyName"", ppt.""TypeName"" , ppst.""SubTypeName"" , pp.""PurchaseUnitQty"" ,pur.""Name"" as ""PurchaseUnitName"",
		                            sale.""Name"" as ""SaleUnitName"", ts.""Status"" , pp.""SaleUnitQty"" ,pp.""IsProductExpire"" as ""IsExpiry"", pp.""PharmacyProductId"", pp.""InventoryItem""		                           
		                            FROM vendors.""PurchaseOrderDetail"" pod
		                            join vendors.""PharmacyProductApproval"" ppa on ppa.""PharmacyProductApprovalId"" = pod.""PharmacyProductApprovalId"" 
		                            join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = ppa.""TenderStatusId"" 
		                            join public.""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppa.""PharmacyProductId"" 
		                            join public.""LookupValue"" cat on cat.""LookupValueId"" = pp.""CategoryId"" 
		                            join public.""LookupValue"" tax on tax.""LookupValueId"" = pp.""TaxId""  
		                            join public.""Company"" c on c.""CompanyId"" = pp.""CompanyId""
		                            left join public.""PharmacyProductType"" ppt on ppt.""PharmacyProductTypeId"" = pp.""PharmacyProductTypeId"" 
		                            left join public.""PharmacyProductSubType"" ppst on ppst.""PharmacyProductSubTypeId"" = pp.""PharmacyProductId"" 
		                            left join public.""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
		                            left join public.""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit""  		                           
		                              {where}
		                            order by pp.""ProductName"" asc;";
            return await this.unitOfWork.Current.QueryAsync<PurchaseOrderDetailModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyPurchaseDetail>> FetchPurchaseBillByPOAsync(PurchaseOrderDetailModel poDetail)
        {
            var query = $@"Select * from public.""PharmacyPurchaseDetail"" where ""PurchaseOrderDetailId"" = {poDetail.PurchaseOrderDetailId}";
            return await this.unitOfWork.Current.QueryAsync<PharmacyPurchaseDetail>(query);
        }

        /// <inheritdoc/>
        public async Task<PharmacyPurchaseHeader> FetchPurchaseHeaderAsync(long purchaseOrderHeaderId)
        {
            var query = $@"SELECT count(*) over() as ""ModifiedBy"" , ""PharmacyPurchaseHeaderId"", ""BillNumber"", ""BillDate"", ""BillType"", ""SupplierId"", ""BillAmount"", ""Discount"", ""Taxes"", ""Netamount"", ""DueDate"", ""AutoGenerateBillNumber"", ""IsCreditClear"", ""PaidOnDate"", ""PharmacyWareHouseId"", ""PayTypeId"", ""PaymentNumber"", ""PurchaseOrderHeaderId""
                                    FROM public.""PharmacyPurchaseHeader"" where ""PurchaseOrderHeaderId"" = {purchaseOrderHeaderId} order by 1 desc limit 1";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PharmacyPurchaseHeader>(query);
        }

        /// <inheritdoc/>
        public async Task<int> VerifyPOCompleteStatusAsync(int purchaseBillHeaderId)
        {
            var findPartialStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Partial PO");
            var findCompleteStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Completed");

            var findPurchase = await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(x => x.PharmacyPurchaseHeaderId == purchaseBillHeaderId);
            if (findPurchase == null)
            {
                return -1;
            }
            var findAllPurchase = (await this.unitOfWork.PharmacyPurchaseHeaders.FindAllAsync(x => x.PurchaseOrderHeaderId == findPurchase.PurchaseOrderHeaderId)).ToList();
            if (findAllPurchase.Count == 0)
            {
                return -1;
            }
            var getPurchaseHeaderId = string.Join(",", findAllPurchase.Select(h => h.PharmacyPurchaseHeaderId));
            var findAllDetail = (await this.unitOfWork.Current.QueryAsync<PharmacyPurchaseDetail>($@"select * from public.""PharmacyPurchaseDetail"" where ""PharmacyPurchaseHeaderId"" in ({getPurchaseHeaderId})")).ToList();
            if (findAllDetail.Count == 0)
            {
                return -1;
            }

            var findPurchaseOrderHeader = await this.unitOfWork.PurchaseOrderHeaders.FindAsync(h => h.PurchaseOrderHeaderId == findPurchase.PurchaseOrderHeaderId);
            if (findPurchaseOrderHeader == null)
            {
                return -1;
            }

            var findAllPurchaseOrderProduct = (await this.unitOfWork.PurchaseOrderDetails.FindAllAsync(d => d.PurchaseOrderHeaderId == findPurchaseOrderHeader.PurchaseOrderHeaderId)).ToList();
            if (findAllPurchaseOrderProduct.Count == 0)
            {
                return -1;
            }
            int partialCount = 0;

            foreach (var addedProd in findAllPurchaseOrderProduct)
            {
                var findAppProd = await this.unitOfWork.PharmacyProductApprovals.FindAsync(p => p.PharmacyProductApprovalId == addedProd.PharmacyProductApprovalId);
                if (findAppProd == null)
                {
                    return -1;
                }

                var getAllPurchase = findAllDetail.FindAll(d => d.PharmacyProductId == findAppProd.PharmacyProductId);

                if (getAllPurchase.Count == 0)
                {
                    continue;
                }

                var diff = addedProd.Quantity - getAllPurchase.Select(x => x.Quantity).Sum();

                if (diff > 0)
                {
                    partialCount++;
                }
                else
                {
                    findAppProd.TenderStatusId = findCompleteStatus.TenderStatusId;
                    await this.unitOfWork.PharmacyProductApprovals.UpdateAsync(findAppProd);
                    var findProdReq = await this.unitOfWork.PharmacyProductRequests.FindAsync(p => p.PharmacyProductRequestId == findAppProd.PharmacyProductRequestId);
                    if (findProdReq != null)
                    {
                        findProdReq.TenderStatusId = findCompleteStatus.TenderStatusId;
                        await this.unitOfWork.PharmacyProductRequests.UpdateAsync(findProdReq);
                    }
                }
            }
            if (partialCount > 0)
            {
                findPurchaseOrderHeader.TenderStatusId = findPartialStatus.TenderStatusId;
                return await this.unitOfWork.PurchaseOrderHeaders.UpdateAsync(findPurchaseOrderHeader);
            }
            else
            {
                findPurchaseOrderHeader.TenderStatusId = findCompleteStatus.TenderStatusId;
                return await this.unitOfWork.PurchaseOrderHeaders.UpdateAsync(findPurchaseOrderHeader);
            }

        }

        /// <inheritdoc/>
        public async Task<int> ApproveOrRejectRequestedProduct(long pharmacyProductRequestId, bool isRejected, int createdBy)
        {
            if (!isRejected)
            {
                var findStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Pending");
                var find = await this.unitOfWork.PharmacyProductRequests.FindAsync(p => p.PharmacyProductRequestId == pharmacyProductRequestId);
                find.ApprovalGivenBy = createdBy;
                find.ApprovalGivenDate = DateTime.Now;
                find.TenderStatusId = findStatus.TenderStatusId;
                return await this.unitOfWork.PharmacyProductRequests.UpdateAsync(find);
            }
            else
            {
                var query = $@"delete from vendors.""PharmacyProductRequest"" ppr where ppr.""PharmacyProductRequestId"" = {pharmacyProductRequestId} ";
                return await this.unitOfWork.Current.ExecuteAsync(query);
            }
        }

        /// <inheritdoc/>
        public async Task<long> AddProductForQuotation(VendorProductApprovalInsertModel model)
        {
            var pending = await this.unitOfWork.TendorStatus.FindAsync(x => x.Status == "Pending");
            var pendingApp = await this.unitOfWork.TendorStatus.FindAsync(x => x.Status == "Waiting For Quotation");
            var header = new ProductForQuotationHeader
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                QuotationNumber = await this.GetQuotationNumber(),
                TenderStatusId = pending.TenderStatusId
            };
            using var transaction = this.unitOfWork.BeginTransaction();
            header.ProductForQuotationHeaderId = await this.unitOfWork.ProductForQuotationHeaders.InsertAsync(header, transaction);

            if (header.ProductForQuotationHeaderId == 0)
            {
                transaction.Rollback();
                return -1;
            }
            foreach (var s in model.Products)
            {
                var detail = new ProductForQuotationDetail
                {
                    PharmacyProductApprovalId = s.PharmacyProductApprovalId,
                    ProductForQuotationHeaderId = header.ProductForQuotationHeaderId,
                    TenderStatusId = pending.TenderStatusId
                };

                detail.ProductForQuotationDetailId = await this.unitOfWork.ProductForQuotationDetails.InsertAsync(detail, transaction);
                if (detail.ProductForQuotationDetailId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
                var productAppr = await this.unitOfWork.PharmacyProductApprovals.FindAsync(p => p.PharmacyProductApprovalId == detail.PharmacyProductApprovalId);
                productAppr.TenderStatusId = pendingApp.TenderStatusId;
                var up = await this.unitOfWork.PharmacyProductApprovals.UpdateAsync(productAppr);
                if (up == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            transaction.Commit();

            return header.ProductForQuotationHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductForQuotationHeaderModel>> FetchRaisedProductForQuotationAsync(ProductForQuotationHeaderModel model)
        {
            var where = $@" where 1=1";
            if (model.ProductForQuotationHeaderId > 0)
            {
                where += $@" and pfqh.""ProductForQuotationHeaderId""= {model.ProductForQuotationHeaderId}";
            }
            var headerQuery = $@"select count(pfqh.*) over() as ""TotalItems"", pfqh.""ProductForQuotationHeaderId"" , pfqh.""QuotationNumber"" , pfqh.""CreatedBy"" , pfqh.""CreatedDate"", pfqh.""TenderStatusId"",
	                                ts.""Status"", a.""FullName"" as ""CreatedByName"" ,
                                    (select count(*) from vendors.""IncomingQuotationHeader"" where ""ProductForQuotationHeaderId"" = pfqh.""ProductForQuotationHeaderId"") as ""QuotationCount""		                              
	                                from vendors.""ProductForQuotationHeader"" pfqh 
	                                join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = pfqh.""TenderStatusId"" 
	                                join ""Account"" a on a.""AccountId"" = pfqh.""CreatedBy"" 
	                                {where}
                                    order by pfqh.""CreatedDate"" desc";
            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                headerQuery += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

            var headerResponse = await this.unitOfWork.Current.QueryAsync<ProductForQuotationHeaderModel>(headerQuery);
            if (!string.IsNullOrEmpty(model.RequireDetail))
            {
                foreach (var header in headerResponse)
                {
                    header.Detail = new List<ProductForQuotationDetailModel>();
                    var sendModel = new ProductForQuotationDetailModel
                    {
                        ProductForQuotationHeaderId = header.ProductForQuotationHeaderId
                    };

                    var response = await this.FetchRaisedProductForQuotationDetailAsync(sendModel);
                    header.Detail.AddRange(response);
                }
            }

            return headerResponse;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductForQuotationDetailModel>> FetchRaisedProductForQuotationDetailAsync(ProductForQuotationDetailModel model)
        {
            var where = $@" where 1=1";
            if (model.ProductForQuotationHeaderId > 0)
            {
                where += $@" and pfqd.""ProductForQuotationHeaderId"" = {model.ProductForQuotationHeaderId}";
            }

            var query = $@"select pfqd.""ProductForQuotationDetailId"" ,pfqd.""PharmacyProductApprovalId"" ,pfqd.""ProductForQuotationHeaderId"", pfqd.""TenderStatusId"",
	                                ts.""Status"" , ppa.""PharmacyProductId"", pp.""ProductName"" , pp.""GenericName"" , pp.""IsGeneralItem"", ppt.""TypeName"", ppst.""SubTypeName"",
	                                pp.""PurchaseUnitQty"" , pp.""SaleUnitQty"" , pur.""Name"" as ""PurchaseUnitName"", sale.""Name"" as ""SaleUnitName"", manu.""Name"" as ""CompanyName"",
	                                cat.""Name"" as ""CategoryName"",tax.""Name""::int as ""Tax"", pp.""InventoryItem""
                                        from vendors.""ProductForQuotationDetail"" pfqd 
		                                join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = pfqd.""TenderStatusId""
		                                join vendors.""PharmacyProductApproval"" ppa on ppa.""PharmacyProductApprovalId"" = pfqd.""PharmacyProductApprovalId"" 
		                                join public.""PharmacyProduct"" pp on pp.""PharmacyProductId"" = ppa.""PharmacyProductId"" 
		                                left join public.""PharmacyProductType"" ppt on ppt.""PharmacyProductTypeId"" = pp.""PharmacyProductTypeId""  
		                                left join public.""PharmacyProductSubType"" ppst on ppst.""PharmacyProductSubTypeId"" = pp.""PharmacyProductSubTypeId""  
		                                join public.""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
		                                join public.""LookupValue"" sale on sale.""LookupValueId"" = pp.""SaleUnit""  
		                                join public.""Company"" manu on manu.""CompanyId"" = pp.""CompanyId"" 
		                                join public.""LookupValue"" cat on cat.""LookupValueId"" = pp.""CategoryId"" 
                                        join public.""LookupValue"" tax on tax.""LookupValueId"" = pp.""TaxId""  
                                        {where}		    
                                        order by pp.""ProductName"" asc;";

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

        /// <inheritdoc/>
        public async Task<int> ModifyInventoryRequestAsync(InventoryProductRequestModel model)
        {
            if (model.InventoryProductRequestId > 0)
            {
                var findOld = await this.unitOfWork.InventoryProductRequests.FindAsync(x => x.InventoryProductRequestId == model.InventoryProductRequestId);
                if (findOld == null)
                {
                    return -1;
                }

                findOld.RequestProductName = model.RequestProductName;
                findOld.PharmacyProductId = model.PharmacyProductId;
                findOld.RequestType = model.RequestType;
                findOld.ModifiedBy = model.CreatedBy;
                findOld.ModifiedDate = DateTime.Now;
                findOld.ReasonForRequest = model.ReasonForRequest;
                findOld.RequestedQuantity = model.RequestedQuantity;
                findOld.LocationId = model.LocationId;
                await this.unitOfWork.InventoryProductRequests.UpdateAsync(findOld);
                return findOld.InventoryProductRequestId;
            }

            var header = new InventoryProductRequest
            {
                PharmacyProductId = model.PharmacyProductId,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                ReasonForRequest = model.ReasonForRequest,
                RequestedQuantity = model.RequestedQuantity,
                RequestProductName = model.RequestProductName,
                RequestType = model.RequestType,
                LocationId = model.LocationId
            };
            return await this.unitOfWork.InventoryProductRequests.InsertAsync(header);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateDocumentUrlForInventoryRequestAsync(InventoryProductRequestModel request)
        {
            var query = $@"update vendors.""InventoryProductRequest"" set  ""DocumentUrl"" = '{request.DocumentUrl}' where ""InventoryProductRequestId"" = {request.InventoryProductRequestId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<InventoryProductRequestModel>> FetchRequestedInventoryProductAsync(InventoryProductRequestModel model)
        {
            var where = $@" where 1=1";

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

            if (model.IsApproved != null)
            {

                where += (bool)model.IsApproved ? $@"and ipr.""PharmacyProductRequestId"" is not null" : $@" and ipr.""PharmacyProductRequestId"" is null";
            }

            var query = $@"select count(ipr.*) over() as ""TotalItems"",  ipr.""InventoryProductRequestId"" , ipr.""PharmacyProductId"" ,ipr.""RequestProductName"" ,ipr.""ReasonForRequest"" ,ipr.""RequestedQuantity"" ,ipr.""RequestType"" ,
		                                ipr.""CreatedBy"" ,ipr.""CreatedDate"" ,ipr.""PharmacyProductRequestId"" ,ipr.""RejectedBy"" ,ipr.""RejectedDate"" ,ipr.""RejectReason"" ,ipr.""ModifiedBy"",ipr.""ModifiedDate"",
			                            ipr.""DocumentUrl"",ipr.""LocationId"", cr.""FullName"" as ""CreatedByName"", m.""FullName"" as ""ModifiedByName"", r.""FullName"" as ""RejectedByName"",
			                            pp.""ProductName"" ,pp.""GenericName"" ,c.""Name""  as ""CompanyName"", pur.""Name"" as ""PurchaseUnitName"",ppr.""PharmacyWareHouseId"" , pwh.""WareHouseName"" ,
			                            ppr.""ApprovalGivenBy"" , app.""FullName"" as ""ApprovalGivenByName"", ppr.""ApprovalGivenDate"" , l.""Name"" as ""LocationName""
			                            from vendors.""InventoryProductRequest"" ipr 
			                            join ""Account"" cr on cr.""AccountId"" = ipr.""CreatedBy"" 
			                            join ""Location"" l on l.""LocationId"" = ipr.""LocationId""
			                            left join ""Account"" m ON m.""AccountId"" = ipr.""ModifiedBy""
			                            left join ""Account"" r ON r.""AccountId"" = ipr.""RejectedBy""
			                            left join ""PharmacyProduct"" pp ON pp.""PharmacyProductId"" = ipr.""PharmacyProductId"" 
			                            left join ""Company"" c on c.""CompanyId"" = pp.""CompanyId"" 
			                            left join ""LookupValue"" pur on pur.""LookupValueId"" = pp.""PurchaseUnit"" 
			                            left join vendors.""PharmacyProductRequest"" ppr on ppr.""PharmacyProductRequestId"" = ipr.""PharmacyProductRequestId""
			                            left join public.""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = ppr.""PharmacyWareHouseId"" 
			                            left join ""Account"" app on app.""AccountId"" = ppr.""ApprovalGivenBy""
                                            {where}
                                        order by ipr.""CreatedDate"" desc";
            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

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

        /// <inheritdoc/>
        public async Task<int> FetchPendingRequestCountAsync()
        {
            var query = $@"select count(*) from vendors.""InventoryProductRequest"" where ""PharmacyProductRequestId"" is null";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
        }

        /// <inheritdoc/>
        public async Task<int> OnUpdateProductInPendingRequestAsync(InventoryProductRequestModel model)
        {
            var find = await this.unitOfWork.InventoryProductRequests.FindAsync(h => h.InventoryProductRequestId == model.InventoryProductRequestId);
            if (find == null)
            {
                return -1;
            }

            find.PharmacyProductId = model.PharmacyProductId;
            find.ModifiedBy = model.CreatedBy;
            find.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            return await this.unitOfWork.InventoryProductRequests.UpdateAsync(find);
        }

        /// <inheritdoc/>
        public async Task<int> OnApproveRequestedProductAsync(InventoryProductRequestModel model)
        {
            var findRequest = await this.unitOfWork.InventoryProductRequests.FindAsync(h => h.InventoryProductRequestId == model.InventoryProductRequestId);
            if (findRequest == null)
            {
                return -1;
            }
            using var transaction = this.unitOfWork.BeginTransaction();

            var findStatus = await this.unitOfWork.TendorStatus.FindAsync(s => s.Status == "Pending");

            var data = new PharmacyProductRequest
            {
                RaisedBy = model.CreatedBy,
                RaisedDate = DateTime.Now,
                PharmacyProductId = (int)model.PharmacyProductId,
                PharmacyWareHouseId = (int)model.PharmacyWareHouseId,
                TenderStatusId = findStatus.TenderStatusId,
                RequestedQuantity = model.RequestedQuantity,
                ApprovalGivenBy = model.CreatedBy,
                ApprovalGivenDate = DateTime.Now.AddMinutes(1),
            };

            data.PharmacyProductRequestId = await this.unitOfWork.PharmacyProductRequests.InsertAsync(data, transaction);
            if (data.PharmacyProductRequestId == 0)
            {
                transaction.Rollback();
                return -1;
            }

            findRequest.PharmacyProductRequestId = data.PharmacyProductRequestId;
            var update = await this.unitOfWork.InventoryProductRequests.UpdateAsync(findRequest, transaction);
            if (update == 0)
            {
                transaction.Rollback();
                return -1;
            }

            transaction.Commit();
            return update;
        }

        /// <inheritdoc/>
        public async Task<int> OnChangeSupplierAtFinalPOAsync(VendorProductForApprovalDisplayModel model)
        {
            var find = await this.unitOfWork.PharmacyProductApprovals.FindAsync(h => h.PharmacyProductApprovalId == model.PharmacyProductApprovalId);
            if (find == null)
            {
                return -1;
            }

            find.SupplierId = model.SupplierId;
            find.PurchaseRate = model.PurchaseRate;
            find.Mrp = model.Mrp;
            find.Free = model.Free;
            return await this.unitOfWork.PharmacyProductApprovals.UpdateAsync(find);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PurchaseBillHeaderModel>> FetchPurchaseBillAddedByGrnAsync(long purchaseOrderHeaderId)
        {
            var where = $@" where 1=1 and PPH.""PurchaseOrderHeaderId"" = {purchaseOrderHeaderId}";

            var query = $@"SELECT PPH.""PharmacyPurchaseHeaderId"", PPH.""BillNumber"", PPH.""BillDate"", PPH.""BillType"", PPH.""SupplierId"", PPH.""BillAmount"", 
		                    PPH.""Discount"", PPH.""Taxes"", PPH.""Netamount"" as ""NetAmount"", PPH.""CreatedBy"", PPH.""CreatedDate"", PPH.""ModifiedBy"", PPH.""ModifiedDate"", PPH.""DueDate"", 
		                    PPH.""AutoGenerateBillNumber"", PPH.""IsCreditClear"", PPH.""PaidOnDate"",PPH.""PharmacyWareHouseId"",PWH.""WareHouseName"", c.""FullName"" as ""CreatedByName""
	                    FROM ""PharmacyPurchaseHeader"" PPH
                        join ""PharmacyWareHouse"" PWH on PWH.""PharmacyWareHouseId"" = PPH.""PharmacyWareHouseId""
                        join ""Account"" c on c.""AccountId""  = pph.""CreatedBy"" 
	                    {where}  order by PPH.""CreatedDate"" desc";

            var headers = await this.unitOfWork.Current.QueryAsync<PurchaseBillHeaderModel>(query);

            foreach (var header in headers)
            {

                header.Products = new List<PurchaseBillDetailModel>();

                var detailQuery = $@"SELECT PPD.""PharmacyPurchaseDetailId"", PPD.""PharmacyPurchaseHeaderId"", PPD.""SerialNum"", PPD.""PharmacyProductId"", 
		                        PPD.""Quantity"", PPD.""Free"", PPD.""PurchaseRate"", PPD.""Mrp"", PPD.""Total"", PPD.""TaxPerItem"", PPD.""TaxAmount"", 
		                        PPD.""DiscountPerItem"", PPD.""DiscountAmount"", PPD.""NetAmount"", PPD.""Barcode"", PPD.""PharmacyStockId"", 
		                        PPD.""PharmacyRetailStockId"", PP.""ProductName"",PP.""GenericName"",Com.""Name"" as ""CompanyName"",PS.""BatchNumber"",
		                        Cat.""Name"" as ""CategoryName"",PP.""TaxId"",PPD.""TaxPerItem""::text as ""TaxPercentage"",PP.""IsProductExpire"" as ""IsExpiry"",
                                PS.""ExpiryDate"",
                                case when PS.""IsIGST"" then 'igst' when PS.""IsSGST"" then 'sgst' else '' end as ""GSTType""
	                        FROM ""PharmacyPurchaseDetail"" PPD
	                        join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PPD.""PharmacyProductId""
	                        join ""Company"" Com on Com.""CompanyId"" = PP.""CompanyId""
	                        join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
                            join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = PPD.""PharmacyStockId""
	                        where PPD.""PharmacyPurchaseHeaderId"" = {header.PharmacyPurchaseHeaderId}";

                header.Products = (await this.unitOfWork.Current.QueryAsync<PurchaseBillDetailModel>(detailQuery)).ToList();
            }
            return headers;
        }

        /// <summary>
        /// Gets the po number.
        /// </summary>
        /// <returns></returns>
        private async Task<string> GetPoNumber()
        {
            var query = $@"Select ""PONumber"" from vendors.""PurchaseOrderHeader"" order by ""PurchaseOrderHeaderId"" desc limit 1";
            var getLatest = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            var fixedText = DateTime.Now.ToString("ddMMyyyy");
            if (getLatest == null)
            {
                return $@"{fixedText}1";
            }
            else
            {
                var check = getLatest[..8];
                if (fixedText == check)
                {
                    var counter = getLatest.Replace(fixedText, string.Empty);
                    return $@"{fixedText}{Convert.ToInt32(counter) + 1}";
                }
                else
                {
                    return $@"{fixedText}1";
                }
            }
        }

        /// <summary>
        /// Fetches the quotation number.
        /// </summary>
        /// <returns></returns>
        private async Task<string> GetQuotationNumber()
        {
            var query = $@" select ""QuotationNumber"" from vendors.""ProductForQuotationHeader"" order by ""ProductForQuotationHeaderId"" desc limit 1";
            var previous = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            var fixedText = "Q";
            if (previous == null)
            {
                var varText = $@"{DateTime.Now:yyyy}1";
                return $@"{fixedText}{varText}";
            }
            else
            {
                var prevBeForeFix = previous.Replace(fixedText, string.Empty);
                var getYear = prevBeForeFix[..4];
                var currentYear = DateTime.Now.ToString("yyyy");
                if (getYear == currentYear)
                {
                    var counter = prevBeForeFix.Replace(currentYear, string.Empty);
                    return $@"{fixedText}{currentYear}{Convert.ToInt64(counter) + 1}";
                }
                else
                {
                    return $@"{fixedText}{currentYear}1";
                }
            }
        }
    }
}