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

    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Configurations;
    using Hims.Domain.Helpers;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels.Pharmacy;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Shared.DataFilters;
    using Shared.UserModels;
    using Shared.UserModels.Vendors;

    using Utilities;

    /// <summary>
    /// The indent controller.
    /// </summary>
    [Authorize]
    [Route("api/initial-vendor")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class InitialVendorController : BaseController
    {
        /// <summary>
        /// The indent service.
        /// </summary>
        private readonly IInitialVendorService initialVendorService;

        /// <summary>
        /// The pharmacy service
        /// </summary>
        private readonly IPharmacyService pharmacyService;

        /// <summary>
        /// The running environment.
        /// </summary>
        private readonly IRunningEnvironment runningEnvironment;

        /// <summary>
        /// The FTP upload helper.
        /// </summary>
        private readonly IFtpUploadHelper ftpUploadHelper;
        /// <inheritdoc />
        public InitialVendorController(
            IInitialVendorService initialVendorService,
            IPharmacyService pharmacyService,
            IRunningEnvironment runningEnvironment,
            IFtpUploadHelper ftpUploadHelper)
        {
            this.initialVendorService = initialVendorService;
            this.pharmacyService = pharmacyService;
            this.ftpUploadHelper = ftpUploadHelper;
            this.runningEnvironment = runningEnvironment;
        }

        /// <summary>
        /// Inserts the product request records asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("insert-request")]
        public async Task<ActionResult> InsertProductRequestRecordsAsync([FromBody] List<PharmacyProductRequestModel> model)
        {
            if (model.Count == 0)
            {
                return BadRequest("Invalid request.");
            }

            var response = await this.initialVendorService.InsertProductRequest(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the product requested records asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-requested-product")]
        public async Task<ActionResult> FetchProductRequestedRecordsAsync([FromBody] PharmacyProductRequestModel model)
        {
            model ??= new PharmacyProductRequestModel();
            var response = await this.initialVendorService.FetchRaisedProductsRequest(model);
            if (model.FetchType != "Awaits Approval")
            {
                foreach (var product in response)
                {
                    product.PriceHistory = new VendorPurchaseProductList();
                    product.PreferedVendor = new VendorPurchaseProductList();
                    var getProductPrice = await this.initialVendorService.FetchVendorPurchaseHistoryAsync(product);
                    product.CompleteVendorList = new VendorPurchaseHistory();
                    product.CompleteVendorList = getProductPrice;
                    if (getProductPrice.FromPreferedVendor.Count > 0)
                    {
                        var result = getProductPrice.FromPreferedVendor.AsQueryable().Min(x => x.PurchaseRate);
                        if (result != null)
                        {
                            product.PriceHistory = getProductPrice.FromPreferedVendor.Find(x => x.PurchaseRate == result);
                            product.PriceAuthority = "Prefered Vendor";
                        }
                    }
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the vendor product purchase records asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-vendor-product-purchase-history")]
        public async Task<ActionResult> FetchVendorProductPurchaseRecordsAsync([FromBody] PharmacyProductRequestModel model)
        {
            model = (PharmacyProductRequestModel)EmptyFilter.Handler(model);
            var response = await this.initialVendorService.FetchVendorPurchaseHistoryAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the approval pending products.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-vendor-product-for-approval")]
        public async Task<ActionResult> AddApprovalPendingProducts([FromBody] VendorProductApprovalInsertModel model)
        {
            if (model.Vendors.Count == 0)
            {
                return this.BadRequest("No product supplied.");
            }

            var response = await this.initialVendorService.AddProductForApprovalAsync(model);
            return this.Success(response);
        }


        /// <summary>Fetches the product pending for final approval asynchronous.</summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-vendor-product-for-approval")]
        public async Task<ActionResult> FetchProductPendingForFinalApprovalAsync([FromBody] VendorProductForApprovalDisplayModel model)
        {
            model ??= new VendorProductForApprovalDisplayModel();
            var response = await this.initialVendorService.FetchPendingForFinalApprovalAsync(model);
            return this.Success(response);
        }

        /// <summary>Fetches the tender for vendors asynchronous.</summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-tender-to-supplier")]
        public async Task<ActionResult> FetchTenderForVendorsAsync([FromBody] VendorViewModel model)
        {
            model ??= new VendorViewModel();
            var response = await this.initialVendorService.FetchSendedPOAsync(model);
            return this.Success(response);
        }


        /// <summary>Fetches the vendor product detail asynchronous.</summary>
        /// <param name="model">The model.</param>
        /// <returns>
        ///   <br />
        /// </returns>
        [HttpPost]
        [Route("fetch-supplier-product-detail")]
        public async Task<ActionResult> FetchVendorProductDetailAsync([FromBody] VendorViewDetailModel model)
        {
            model ??= new VendorViewDetailModel();
            var response = await this.initialVendorService.FetchVendorProductDetailsAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the vendor approved products asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("vendor-approved-products")]
        public async Task<ActionResult> FetchVendorApprovedProductsAsync([FromBody] VendorViewDetailModel model)
        {
            model ??= new VendorViewDetailModel();
            var response = await this.initialVendorService.FetchApprovedProductsForVendorAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the direct product to request asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-direct-product-request")]
        public async Task<ActionResult> AddDirectProductToRequestAsync([FromBody] VendorProductForApprovalModel model)
        {
            model = (VendorProductForApprovalModel)EmptyFilter.Handler(model);
            if (model.Product.Count == 0)
            {
                return this.BadRequest("No product supplied.");
            }
            var response = await this.initialVendorService.AddDirectProductAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Raises the po asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("raise-po")]
        public async Task<ActionResult> RaisePOAsync([FromBody] List<VendorProductApprovalInsertModel> model)
        {
            if (model.Count == 0)
            {
                return this.BadRequest("Please add values before submitting.");
            }
            var ids = new List<long>();
            foreach (var item in model)
            {
                var response = await this.initialVendorService.RaisePOAsync(item);
                if (response <= 0)
                {
                    return this.ServerError();
                }
                ids.Add(response);
            }
            return this.Success(string.Join(",", ids.Select(x => x)));
        }

        /// <summary>
        /// Fetches the po header asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-po-header")]
        public async Task<ActionResult> FetchPOHeaderAsync([FromBody] PurchaseOrderHeaderModel model)
        {
            model ??= new PurchaseOrderHeaderModel();
            var response = await this.initialVendorService.FetchPurchaseOrderHeaderAsync(model);
            if (!string.IsNullOrEmpty(model.Source) && model.Source == "grn")
            {
                foreach (var item in response)
                {
                    var added = await this.initialVendorService.FetchPurchaseHeaderAsync(item.PurchaseOrderHeaderId);
                    if (added != null && added.PharmacyPurchaseHeaderId > 0)
                    {
                        item.DueDate = added.DueDate;
                        item.TotalBillCount = added.ModifiedBy;
                    }
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the po detial asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-po-detail")]
        public async Task<ActionResult> FetchPODetialAsync([FromBody] PurchaseOrderDetailModel model)
        {
            model ??= new PurchaseOrderDetailModel();
            var response = (await this.initialVendorService.FetchPurchaseOrderDetailAsync(model)).ToList();

            if (!string.IsNullOrEmpty(model.Source) && model.Source == "grn")
            {
                var intCount = new List<long>();
                var count = 0;
                foreach (var item in response)
                {
                    count++;
                    var getData = (await this.initialVendorService.FetchPurchaseBillByPOAsync(new PurchaseOrderDetailModel { PurchaseOrderDetailId = item.PurchaseOrderDetailId })).ToList();
                    if (getData.Count > 0)
                    {
                        foreach (var data in getData)
                        {
                            item.Quantity -= data.Quantity;
                            item.Free -= data.Free;
                            if(item.Free < 0)
                            {
                                item.Free = 0;
                            }
                        }
                    }
                    if (item.Quantity == 0)
                    {
                        intCount.Add(item.PurchaseOrderDetailId);
                    }
                }

                foreach (var item in intCount)
                {
                    var getIndex = response.FindIndex(x => x.PurchaseOrderDetailId == item);
                    if (getIndex > -1)
                    {
                        response.RemoveAt(getIndex);
                    }
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the po number asynchronous.
        /// </summary>
        /// <param name="poNum">The po number.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-po-number")]
        public async Task<ActionResult> FetchPONumberAsync(string poNum)
        {
            var response = await this.initialVendorService.FetchOnlyPONumberAsync(poNum);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the purchase bill from po asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-grn")]
        public async Task<ActionResult> AddPurchaseBillFromPOAsync([FromBody] PurchaseBillHeaderModel model)
        {
            model = (PurchaseBillHeaderModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyService.AddNewPurchaseBill(model);
            var secondResponse = await this.initialVendorService.VerifyPOCompleteStatusAsync(response);
            return this.Success(secondResponse);
        }

        /// <summary>
        /// Fetches the purchase bill added by GRN asynchronous.
        /// </summary>
        /// <param name="purchaseOrderHeaderId">The purchase order header identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-added-purchase-by-grn")]
        public async Task<ActionResult> FetchPurchaseBillAddedByGrnAsync(long purchaseOrderHeaderId)
        {
            if(purchaseOrderHeaderId == 0) { return this.BadRequest("Invalid parameter passed."); }
            var response = await this.initialVendorService.FetchPurchaseBillAddedByGrnAsync(purchaseOrderHeaderId);
            return this.Success(response);
        }

        /// <summary>
        /// Approves the or reject requested products asynchronous.
        /// </summary>
        /// <param name="pharmacyProductRequestId">The pharmacy product request identifier.</param>
        /// <param name="isRejected">if set to <c>true</c> [is rejected].</param>
        /// <param name="createdBy">The created by.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("approve-or-reject-product")]
        public async Task<ActionResult> ApproveOrRejectRequestedProductsAsync(long pharmacyProductRequestId, bool isRejected, int createdBy)
        {
            if (pharmacyProductRequestId == 0)
            {
                return this.BadRequest("Unable to complete operation.Please try after sometime.");
            }
            var response = await this.initialVendorService.ApproveOrRejectRequestedProduct(pharmacyProductRequestId, isRejected, createdBy);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the product for quotation asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-for-quotation")]
        public async Task<ActionResult> AddProductForQuotationAsync([FromBody] VendorProductApprovalInsertModel model)
        {
            model = (VendorProductApprovalInsertModel)EmptyFilter.Handler(model);
            var response = await this.initialVendorService.AddProductForQuotation(model);
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the product for quotation asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-product-for-quotation")]
        public async Task<ActionResult> FetchProductForQuotationAsync([FromBody] ProductForQuotationHeaderModel model)
        {
            model ??= new ProductForQuotationHeaderModel();
            var response = await this.initialVendorService.FetchRaisedProductForQuotationAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Modifies the inventory request asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("modify-inventory-request")]
        [Consumes("multipart/form-data")]
        public async Task<ActionResult> ModifyInventoryRequestAsync([FromForm] InventoryProductRequestModel model, [FromHeader] LocationHeader location)
        {
            model = (InventoryProductRequestModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(location.LocationId);
            var response = await this.initialVendorService.ModifyInventoryRequestAsync(model);
            if (response > 0)
            {
                model.InventoryProductRequestId = response;
                var files = this.Request.Form.Files;
                if (files.Count > 0)
                {
                    #region FTP
                    var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/InventoryRequest/{model.InventoryProductRequestId}";
                    await this.ftpUploadHelper.CreateDirectory(filePath);
                    var dbPath = $@"{files[0].FileName}";
                    filePath += $@"/{dbPath}";
                    var uploadResponse = await this.ftpUploadHelper.UploadFromFileAsync(filePath, files[0]);
                    if (uploadResponse <= 0)
                    {
                        return this.BadRequest();
                    }
                    #endregion
                    model.DocumentUrl = $@"{dbPath}";

                    await this.initialVendorService.UpdateDocumentUrlForInventoryRequestAsync(model);
                }
            }

            return this.Success(response);
        }

        /// <summary>
        /// Fetches the inventory requested products asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-inventory-request")]
        public async Task<ActionResult> FetchInventoryRequestedProductsAsync([FromBody] InventoryProductRequestModel model)
        {
            model ??= new InventoryProductRequestModel();
            var response = await this.initialVendorService.FetchRequestedInventoryProductAsync(model);
            foreach (var item in response)
            {
                if (!string.IsNullOrEmpty(item.DocumentUrl))
                {
                    var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/InventoryRequest/{item.InventoryProductRequestId}";
                    item.DocumentUrl = $@"{filePath}/{item.DocumentUrl}";
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the pending inventory request asynchronous.
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-pending-inventory-request")]
        public async Task<ActionResult> FetchPendingInventoryRequestAsync()
        {
            return this.Success(await this.initialVendorService.FetchPendingRequestCountAsync());
        }

        /// <summary>
        /// Updates the product in request asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("update-product-for-pending-inventory-request")]
        public async Task<ActionResult> UpdateProductInRequestAsync([FromBody] InventoryProductRequestModel model)
        {
            model = (InventoryProductRequestModel)EmptyFilter.Handler(model);
            var response = await this.initialVendorService.OnUpdateProductInPendingRequestAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Approves the product inventory request asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("approve-inventory-request")]
        public async Task<ActionResult> ApproveProductInventoryRequestAsync([FromBody] InventoryProductRequestModel model)
        {
            model = (InventoryProductRequestModel)EmptyFilter.Handler(model);
            var response = await this.initialVendorService.OnApproveRequestedProductAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Called when [change vendor at final po asynchronous].
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("change-vendor-at-po")]
        public async Task<ActionResult> OnChangeVendorAtFinalPOAsync([FromBody] VendorProductForApprovalDisplayModel model)
        {
            model = (VendorProductForApprovalDisplayModel)EmptyFilter.Handler(model);
            var res = await this.initialVendorService.OnChangeSupplierAtFinalPOAsync(model);
            return this.Success(res);
        }
    }
}
