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

    using Domain.Services;

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

    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.UserModels;
    using Shared.UserModels.Pharmacy;
    using Shared.UserModels.ExcelUploads;
    using Shared.Library.Enums;

    using Utilities;
    using Hims.Api.Models;

    /// <summary>
    /// The pharmacy controller.
    /// </summary>
    [Authorize]
    [Route("api/pharmacy-import")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class PharmacyImportController : BaseController
    {
        /// <summary>
        /// The pharmacy service.
        /// </summary>
        private readonly IPharmacyService pharmacyService;

        /// <summary>
        /// The pharmacy log services.
        /// </summary>
        private readonly IPharmacyLogService pharmacyLogServices;

        /// <summary>
        /// The company service.
        /// </summary>
        private readonly ICompanyService companyService;

        /// <summary>
        /// The supplier service.
        /// </summary>
        private readonly ISupplierService supplierService;

        /// <summary>
        /// The excel upload history service.
        /// </summary>
        private readonly IExcelUploadHistoryService excelUploadHistoryService;

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

        /// <summary>
        /// The pharmacy ware house service.
        /// </summary>
        private readonly IPharmacyWareHouseService pharmacyWareHouseService;

        /// <summary>
        /// The pharmacy department service.
        /// </summary>
        private readonly IPharmacyDepartmentService pharmacyDepartmentService;

        /// <summary>
        /// The issue service.
        /// </summary>
        private readonly IIssueService issueService;

        /// <inheritdoc />
        public PharmacyImportController(
            IPharmacyService pharmacyService,
            IPharmacyLogService pharmacyLogServices,
            ICompanyService companyService,
            ISupplierService supplierService,
            IExcelUploadHistoryService excelUploadHistoryService,
            IAuditLogService auditLogServices,
            IPharmacyWareHouseService pharmacyWareHouseService,
            IPharmacyDepartmentService pharmacyDepartmentService,
            IIssueService issueService)
        {
            this.pharmacyService = pharmacyService;
            this.pharmacyLogServices = pharmacyLogServices;
            this.companyService = companyService;
            this.supplierService = supplierService;
            this.excelUploadHistoryService = excelUploadHistoryService;
            this.auditLogServices = auditLogServices;
            this.pharmacyWareHouseService = pharmacyWareHouseService;
            this.pharmacyDepartmentService = pharmacyDepartmentService;
            this.issueService = issueService;
        }

        /// <summary>
        /// The add products from excel async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="header"></param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("add-product-sheet")]
        public async Task<ActionResult> AddProductsFromExcelAsync([FromBody] ExcelPharmacyProduct model, [FromHeader] LocationHeader header)
        {
            model = (ExcelPharmacyProduct)EmptyFilter.Handler(model);
            if (model.Products.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }
            var productList = await this.AddPharmacyProductAsync(model);

            var excelHistory = new ExcelUploadHistoryModel
            {
                ExcelUploadHistoryId = model.ExcelUploadHistoryId,
                AddedProducts = string.Join(",", productList.Select(m => m.PharmacyProductId)),
                SheetName = model.SheetName,
                SheetType = "Pharmacy Product Sheet",
                TypeOf = "P",
                UploadedBy = model.CreatedBy,
                ProductStatus = string.Join(",", productList.Select(m => m.IsGetProductId)),
                LocationId = Convert.ToInt32(header.LocationId)
            };

            var response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

            if (model.IsCreateLog)
            {
                try
                {
                    var record = await this.excelUploadHistoryService.GetSingleExcelHistory(response);
                    var iLogs = new PharmacyLogModel
                    {
                        AccountId = model.CreatedBy,
                        PharmacyLogTypeId = (int)PharmacyLogTypes.ExcelProductSheet,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Excel sheet with <b>{record.AddedProducts.Split(",").Length} products</b> has been <b>Added</b> Successfully",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.pharmacyLogServices.LogAsync(iLogs);

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.CreatedBy,
                        LogTypeId = (int)LogTypes.ExcelSheet,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New excel sheet <b>{model.SheetName}</b> has been uploaded.",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception)
                {
                    //logs
                }
            }

            return this.Success(response);
        }

        /// <summary>
        /// The add products from excel with purchase bill async.
        /// </summary>
        /// <param name="models">
        /// The model.
        /// </param>
        /// <param name="header"></param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("add-product-sheet-with-purchase-bill")]
        public async Task<ActionResult> AddProductsFromExcelWithPurchaseBillAsync([FromBody] ExcelPharmacyProductWithPurchaseBillModel models, [FromHeader] LocationHeader header)
        {
            models = (ExcelPharmacyProductWithPurchaseBillModel)EmptyFilter.Handler(models);
            if (models.PurchaseBills.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }
            int response = 0;

            var ids = new List<int>();
            foreach (var model in models.PurchaseBills)
            {
                var transformedRecord = new ExcelPharmacyProduct();
                transformedRecord.Products = new List<RawProductsModel>();
                transformedRecord.Products.AddRange(model.Products);
                model.CreatedBy = transformedRecord.CreatedBy = models.CreatedBy;


                var productList = await this.AddPharmacyProductAsync(transformedRecord);

                var billResponse = await this.AddPurchaseBillFromExcel(productList, model);

                ids.Add(billResponse);
            }


            var excelHistory = new ExcelUploadHistoryModel
            {
                ExcelUploadHistoryId = models.ExcelUploadHistoryId,
                AddedProducts = string.Join(",", ids.Select(m => m)),
                SheetName = models.SheetName,
                SheetType = "Pharmacy Purchase Sheet",
                TypeOf = "P",
                UploadedBy = models.CreatedBy,
                ProductStatus = string.Empty,
                LocationId = Convert.ToInt32(header.LocationId)
            };

            response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

            if (models.IsCreateLog)
            {
                try
                {
                    var record = await this.excelUploadHistoryService.GetSingleExcelHistory(response);
                    var iLogs = new PharmacyLogModel
                    {
                        AccountId = models.CreatedBy,
                        PharmacyLogTypeId = (int)PharmacyLogTypes.ExcelProductSheet,
                        LogFrom = (short)models.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Excel sheet with <b>{record.AddedProducts.Split(",").Length} products and purchase bill</b> has been <b>Added</b> Successfully",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.pharmacyLogServices.LogAsync(iLogs);

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = models.CreatedBy,
                        LogTypeId = (int)LogTypes.ExcelSheet,
                        LogFrom = (short)models.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New excel sheet <b>{models.SheetName}</b> has been uploaded.",
                        LocationId = Convert.ToInt32(header.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception)
                {
                    //logs
                }
            }

            return this.Success(response);
        }

        /// <summary>
        /// The fetch all excel upload history.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-upload-history")]
        public async Task<ActionResult> FetchAllExcelUploadHistory([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = await this.excelUploadHistoryService.FetchAllAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch all excel products async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-uploaded-products")]
        public async Task<ActionResult> FetchAllExcelProductsAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = (await this.pharmacyService.FetchPharmacyProduct(new ProductModel { BulkProductIds = model.AddedProducts })).ToList();
            var productArray = model.AddedProducts.Split(",");
            var productStatusArray = model.ProductStatus.Split(",");
            var productList = new List<ProductModel>();
            for (int i = 0; i < productArray.Length; i++)
            {
                var productId = int.Parse(productArray[i]);
                var status = bool.Parse(productStatusArray[i]);
                var product = response.Find(m => m.PharmacyProductId == productId);
                if (status)
                {
                    product.IsGetProductId = true;
                }
                productList.Add(product);
            }

            return this.Success(productList);
        }

        /// <summary>
        /// The fetch all excel purchase bill async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        [HttpPost]
        [Route("fetch-uploaded-purchase-bills")]
        public async Task<ActionResult> FetchAllExcelPurchaseBillAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);

            var ids = model.AddedProducts.Split(",");
            var allIds = new List<int>();
            foreach (var id in ids)
            {
                allIds.Add(int.Parse(id));
            }

            var distinctId = allIds.Distinct().ToArray();
            var billsList = new List<AddedPurchaseBillFromExcelModel>();
            foreach (var id in distinctId)
            {
                if (id > 0)
                {
                    var singleBill = new AddedPurchaseBillFromExcelModel
                    {
                        Bills = new List<PharmacyBillModel>()
                    };
                    var purchaseBill = (await this.pharmacyService.FetchAddedPurchaseBillAsync(id, string.Empty)).ToList();
                    singleBill.BillNumber = purchaseBill[0].BillNumber;
                    singleBill.PharmacyPurchaseHeaderId = purchaseBill[0].PharmacyPurchaseHeaderId;

                    singleBill.Bills = purchaseBill;
                    billsList.Add(singleBill);
                }
            }

            return this.Success(billsList);
        }

        /// <summary>
        /// Adds the ware houses from excel asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-warehouse-record")]
        public async Task<ActionResult> AddWareHousesFromExcelAsync([FromBody] PharmacyWareHouseUploadModel model, [FromHeader] LocationHeader location)
        {
            model = (PharmacyWareHouseUploadModel)EmptyFilter.Handler(model);
            if (model.WareHouses.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }

            var uploadedId = new List<PharmacyWareHouseModel>();
            foreach (var item in model.WareHouses)
            {
                var wareHouseModel = new PharmacyWareHouseModel
                {
                    Active = true,
                    CreatedBy = model.CreatedBy,
                    WareHouseName = item.WareHouseName
                };

                if (!string.IsNullOrEmpty(item.Location))
                {
                    var locations = await this.pharmacyWareHouseService.GetLocationIdBasedOnNameAsync(item.Location);
                    if (!string.IsNullOrEmpty(item.IsCentral) && item.IsCentral.ToLower() == "y")
                    {
                        wareHouseModel.CentralWarehouseLocationId = locations.ToList()[0].LocationId;
                    }
                    else
                    {
                        wareHouseModel.LocationId = locations.ToList()[0].LocationId;
                    }
                }

                int isAlreadyExists;
                if (wareHouseModel.CentralWarehouseLocationId != null && wareHouseModel.LocationId == null)
                {
                    var query = $@"select pwh.""PharmacyWareHouseId"" from ""PharmacyWareHouse"" pwh where lower(pwh.""WareHouseName"") = lower('{wareHouseModel.WareHouseName}') and pwh.""CentralWarehouseLocationId"" = {wareHouseModel.CentralWarehouseLocationId}";
                    isAlreadyExists = await this.pharmacyWareHouseService.CheckWareHouseByNameAndLocationAsync(query);
                }
                else if (wareHouseModel.CentralWarehouseLocationId == null && wareHouseModel.LocationId != null)
                {
                    var query = $@"select pwh.""PharmacyWareHouseId"" from ""PharmacyWareHouse"" pwh where lower(pwh.""WareHouseName"") = lower('{wareHouseModel.WareHouseName}') and pwh.""LocationId"" = {wareHouseModel.LocationId}";
                    isAlreadyExists = await this.pharmacyWareHouseService.CheckWareHouseByNameAndLocationAsync(query);
                }
                else
                {
                    isAlreadyExists = 0;
                }

                if (isAlreadyExists > 0)
                {
                    wareHouseModel.IsUploaded = false;
                    wareHouseModel.PharmacyWareHouseId = isAlreadyExists;
                }
                else
                {
                    wareHouseModel.IsUploaded = true;
                    wareHouseModel.PharmacyWareHouseId = await this.pharmacyWareHouseService.InsertPharmacyWareHouse(wareHouseModel);
                }
                uploadedId.Add(wareHouseModel);
            }
            if (uploadedId.Count > 0)
            {
                var excelHistory = new ExcelUploadHistoryModel
                {
                    ExcelUploadHistoryId = model.ExcelUploadHistoryId,
                    AddedProducts = string.Join(",", uploadedId.Select(m => m.PharmacyWareHouseId)),
                    SheetName = model.SheetName,
                    SheetType = "Pharmacy WareHouse Sheet",
                    TypeOf = "P",
                    UploadedBy = model.CreatedBy,
                    ProductStatus = string.Join(",", uploadedId.Select(m => m.IsUploaded)),
                    LocationId = Convert.ToInt32(location.LocationId)
                };

                var response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

                return this.Success(response);
            }

            return this.BadRequest("Invalid Sheet.");

        }

        /// <summary>
        /// Fetches the uploaded ware houses asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-uploaded-warehouse")]
        public async Task<ActionResult> FetchUploadedWareHousesAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = (await this.pharmacyWareHouseService.FetchAllWarehousesAsync(new PharmacyWareHouseModel { WarehouseIds = model.AddedProducts })).ToList();
            var productArray = model.AddedProducts.Split(",");
            var productStatusArray = model.ProductStatus.Split(",");
            var wareHouseList = new List<PharmacyWareHouseModel>();
            for (int i = 0; i < productArray.Length; i++)
            {
                var warehouseId = int.Parse(productArray[i]);
                if (warehouseId > 0)
                {
                    var status = bool.Parse(productStatusArray[i]);
                    var product = response.Find(m => m.PharmacyWareHouseId == warehouseId);
                    if (status)
                    {
                        product.IsUploaded = true;
                    }
                    wareHouseList.Add(product);
                }
            }

            return this.Success(wareHouseList);
        }

        /// <summary>
        /// Adds the retail store from excel asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-retail-store-record")]
        public async Task<ActionResult> AddRetailStoreFromExcelAsync([FromBody] ExcelRetailStoreSheetModel model, [FromHeader] LocationHeader location)
        {
            model = (ExcelRetailStoreSheetModel)EmptyFilter.Handler(model);
            if (model.Stores.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }

            var uploadedId = new List<RetailPharmacyModel>();

            foreach (var item in model.Stores)
            {
                var warehouseNames = string.Join(",", item.MatchedWarehouses.Select(x => x));
                var finalNames = $@"'{warehouseNames.Replace(",", "','")}'";

                var warehouses = await this.pharmacyWareHouseService.GetOnlyWareHousesWithLocationAsync(finalNames);

                var locations = (await this.pharmacyWareHouseService.GetLocationIdBasedOnNameAsync(item.Location)).ToList();

                var retailModel = new RetailPharmacyModel
                {
                    RetailPharmacyId = 0,
                    Active = true,
                    AllowedAccountId = null,
                    AllowedUser = null,
                    CreatedBy = model.CreatedBy,
                    PharmacyWareHouseIds = string.Join(",", warehouses.Select(x => x.PharmacyWareHouseId)),
                    RetailName = item.RetailStore,
                    LocationId = locations[0].LocationId
                };

                retailModel.RetailPharmacyId = await this.pharmacyService.CreateRetailStoreAsync(retailModel);
                if (retailModel.RetailPharmacyId > 0)
                {
                    retailModel.IsUploaded = true;
                }
                else if (retailModel.RetailPharmacyId < 0)
                {
                    var query = $@"SELECT ""RetailPharmacyId""	FROM ""RetailPharmacy"" where lower(""RetailName"") = lower('{retailModel.RetailName}')";
                    retailModel.RetailPharmacyId = await this.pharmacyWareHouseService.CheckWareHouseByNameAndLocationAsync(query);
                    retailModel.IsUploaded = false;
                }

                uploadedId.Add(retailModel);
            }
            if (uploadedId.Count > 0)
            {
                var excelHistory = new ExcelUploadHistoryModel
                {
                    ExcelUploadHistoryId = model.ExcelUploadHistoryId,
                    AddedProducts = string.Join(",", uploadedId.Select(m => m.RetailPharmacyId)),
                    SheetName = model.SheetName,
                    SheetType = "Retail Store Sheet",
                    TypeOf = "P",
                    UploadedBy = model.CreatedBy,
                    ProductStatus = string.Join(",", uploadedId.Select(m => m.IsUploaded)),
                    LocationId = Convert.ToInt32(location.LocationId)
                };

                var response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

                return this.Success(response);
            }

            return this.BadRequest("Invalid Sheet.");

        }

        /// <summary>
        /// Fetches the uploaded retail store asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-uploaded-retail-stores")]
        public async Task<ActionResult> FetchUploadedRetailStoreAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = (await this.pharmacyService.FetchAllRetailStores(new RetailPharmacyModel { RetailPharmacyIds = model.AddedProducts })).ToList();
            var productArray = model.AddedProducts.Split(",");
            var productStatusArray = model.ProductStatus.Split(",");
            var storeList = new List<RetailPharmacyModel>();
            for (int i = 0; i < productArray.Length; i++)
            {
                var retailId = int.Parse(productArray[i]);
                if (retailId > 0)
                {
                    var status = bool.Parse(productStatusArray[i]);
                    var product = response.Find(m => m.RetailPharmacyId == retailId);
                    if (status)
                    {
                        product.IsUploaded = true;
                    }
                    storeList.Add(product);
                }
            }

            return this.Success(storeList);
        }

        /// <summary>
        /// Adds the department from excel asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-department-record")]
        public async Task<ActionResult> AddDepartmentFromExcelAsync([FromBody] ExcelRetailStoreSheetModel model, [FromHeader] LocationHeader location)
        {
            model = (ExcelRetailStoreSheetModel)EmptyFilter.Handler(model);
            if (model.Departments.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }

            var uploadedId = new List<PharmacyDepartmentModel>();

            foreach (var item in model.Departments)
            {
                var locations = (await this.pharmacyWareHouseService.GetLocationIdBasedOnNameAsync(item.Location)).ToList();

                var departmentModel = new PharmacyDepartmentModel
                {
                    PharmacyDepartmentId = 0,
                    Active = true,
                    CreatedBy = model.CreatedBy,
                    LocationId = locations[0].LocationId,
                    Name = item.DepartmentName
                };

                departmentModel.PharmacyDepartmentId = await this.pharmacyDepartmentService.ModifyDepartment(departmentModel);
                if (departmentModel.PharmacyDepartmentId > 0)
                {
                    departmentModel.IsUploaded = true;
                }
                else if (departmentModel.PharmacyDepartmentId < 0)
                {
                    var query = $@"SELECT ""PharmacyDepartmentId""	FROM ""PharmacyDepartment"" where lower(""Name"") = '{departmentModel.Name.ToLower()}' and ""LocationId"" = {departmentModel.LocationId}";
                    departmentModel.PharmacyDepartmentId = await this.pharmacyWareHouseService.CheckWareHouseByNameAndLocationAsync(query);
                    departmentModel.IsUploaded = false;
                }

                uploadedId.Add(departmentModel);
            }
            if (uploadedId.Count > 0)
            {
                var excelHistory = new ExcelUploadHistoryModel
                {
                    ExcelUploadHistoryId = model.ExcelUploadHistoryId,
                    AddedProducts = string.Join(",", uploadedId.Select(m => m.PharmacyDepartmentId)),
                    SheetName = model.SheetName,
                    SheetType = "Department Store Sheet",
                    TypeOf = "P",
                    UploadedBy = model.CreatedBy,
                    ProductStatus = string.Join(",", uploadedId.Select(m => m.IsUploaded)),
                    LocationId = Convert.ToInt32(location.LocationId)
                };

                var response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

                return this.Success(response);
            }

            return this.BadRequest("Invalid Sheet.");

        }

        /// <summary>
        /// Fetches the uploaded departments asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-uploaded-departments")]
        public async Task<ActionResult> FetchUploadedDepartmentsAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = (await this.pharmacyDepartmentService.FetchAllPharmacyDepartmentWithoutUsersAsync(new PharmacyDepartmentModel { PharmacyDepartmentIds = model.AddedProducts })).ToList();
            var productArray = model.AddedProducts.Split(",");
            var productStatusArray = model.ProductStatus.Split(",");
            var storeList = new List<PharmacyDepartmentModel>();
            for (int i = 0; i < productArray.Length; i++)
            {
                var departmentId = int.Parse(productArray[i]);
                if (departmentId > 0)
                {
                    var status = bool.Parse(productStatusArray[i]);
                    var product = response.Find(m => m.PharmacyDepartmentId == departmentId);
                    if (status)
                    {
                        product.IsUploaded = true;
                    }
                    storeList.Add(product);
                }
            }

            return this.Success(storeList);
        }

        /// <summary>
        /// Adds the retail store stock from excel asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("upload-retail-store-stocks")]
        public async Task<ActionResult> AddRetailStoreStockFromExcelAsync([FromBody] ExcelRetailStoreSheetModel model, [FromHeader] LocationHeader location)
        {
            model = (ExcelRetailStoreSheetModel)EmptyFilter.Handler(model);
            if (model.RetailStock.Count == 0)
            {
                return this.BadRequest("Invalid sheet");
            }

            var retailStockIds = new List<int>();

            foreach (var item in model.RetailStock)
            {
                var transformedRecord = new ExcelPharmacyProduct();
                transformedRecord.Products = new List<RawProductsModel>();
                transformedRecord.Products.AddRange(item.Data);
                transformedRecord.CreatedBy = model.CreatedBy;
                var productList = await this.AddPharmacyProductAsync(transformedRecord);

                var getLinkId = await this.issueService.RetailWareHouseLinkIdAsync(item.PharmacyWareHouseId, item.RetailPharmacyId);
                if (getLinkId > 0)
                {
                    foreach (var product in productList)
                    {
                        var getRestOfProductRecord = item.Data.Find(x => x.ProductName == product.ProductName && x.BatchNumber == product.BatchNumber);
                        var retailStock = new PharmacyRetailStockModel
                        {
                            Mrp = Math.Round(Convert.ToDouble(getRestOfProductRecord.Mrp), 2),
                            PurchaseRate = Math.Round(Convert.ToDouble(getRestOfProductRecord.PurchaseRate), 2),
                            Barcode = product.Barcode,
                            BatchNumber = getRestOfProductRecord.BatchNumber,
                            CreatedBy = model.CreatedBy,
                            ExpiryDate = product.IsProductExpire && !string.IsNullOrEmpty(getRestOfProductRecord.ExpiryDate) ? Convert.ToDateTime(getRestOfProductRecord.ExpiryDate) : (DateTime?)null,
                            QuantityIn = Convert.ToInt32(getRestOfProductRecord.Quantity),
                            QuantityOut = 0,
                            TaxId = product.TaxId,
                            RetailWareHouseLinkId = getLinkId,
                            PharmacyProductId = product.PharmacyProductId
                        };

                        var retailStockId = await this.issueService.AddRetailStoreStockFromExcelSheetAsync(retailStock);
                        if (retailStockId > 0)
                        {
                            retailStockIds.Add(retailStockId);
                        }
                    }
                }

            }



            var excelHistory = new ExcelUploadHistoryModel
            {
                ExcelUploadHistoryId = model.ExcelUploadHistoryId,
                AddedProducts = string.Join(",", retailStockIds.Select(m => m)),
                SheetName = model.SheetName,
                SheetType = "Pharmacy Retail Stock Sheet",
                TypeOf = "P",
                UploadedBy = model.CreatedBy,
                ProductStatus = string.Empty,
                LocationId = Convert.ToInt32(location.LocationId)
            };

            var response = await this.excelUploadHistoryService.ModifyExcelUploadAsync(excelHistory);

            if (model.IsCreateLog)
            {
                try
                {
                    var iLogs = new PharmacyLogModel
                    {
                        AccountId = model.CreatedBy,
                        PharmacyLogTypeId = (int)PharmacyLogTypes.ExcelProductSheet,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Excel sheet with <b>retail store stocks</b> has been <b>Added</b> Successfully",
                        LocationId = Convert.ToInt32(location.LocationId)
                    };
                    await this.pharmacyLogServices.LogAsync(iLogs);

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = model.CreatedBy,
                        LogTypeId = (int)LogTypes.ExcelSheet,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New excel sheet <b>{model.SheetName}</b> has been uploaded.",
                        LocationId = Convert.ToInt32(location.LocationId)
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception)
                {
                    //logs
                }
            }

            return this.Success(response);
        }

        /// <summary>
        /// Fetches the uploaded retail stocks asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("fetch-uploaded-retail-stocks")]
        public async Task<ActionResult> FetchUploadedRetailStocksAsync([FromBody] ExcelUploadHistoryModel model)
        {
            model = (ExcelUploadHistoryModel)EmptyFilter.Handler(model);
            var response = await this.pharmacyService.FetchPharmacyRetailStocks(new PharmacyStockModel { PharmacyRetailStockIds = model.AddedProducts, UnavailableStock = "yes" });
            return this.Success(response);
        }



        /// <summary>
        /// The add pharmacy product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        private async Task<List<ProductModel>> AddPharmacyProductAsync(ExcelPharmacyProduct model)
        {
            var totalProductList = new List<ProductModel>();

            foreach (var product in model.Products)
            {
                var singleProduct = new ProductModel();
                var checkCompanyExits = await this.companyService.FetchAsync(new CompanyModel { TypeOf = "pharmacyCompany", Name = product.Company });
                if (checkCompanyExits == null)
                {
                    var newCompany = new CompanyModel
                    {
                        Name = product.Company,
                        TypeOf = "pharmacyCompany",
                        Location = "Hyderabad",
                        CreatedBy = model.CreatedBy
                    };

                    newCompany.CompanyId = await this.companyService.InsertCompanyAsync(newCompany);
                    singleProduct.CompanyId = newCompany.CompanyId;
                }
                else
                {
                    singleProduct.CompanyId = checkCompanyExits.CompanyId;
                }
                LookupValueModel lookupModel = new LookupValueModel();
                lookupModel.CreatedBy = model.CreatedBy;
                lookupModel.Name = "PharmacyCategory";
                lookupModel.LookupValueName = product.Category;
                var category = await this.CommonLookupValuesAsync(lookupModel);
                singleProduct.CategoryId = category.LookupValueId;

                lookupModel.Name = "PharmacyUnit";
                lookupModel.LookupValueName = product.SaleUnit;
                var saleUnit = await this.CommonLookupValuesAsync(lookupModel);
                singleProduct.SaleUnit = saleUnit.LookupValueId;

                lookupModel.Name = "PharmacyUnit";
                lookupModel.LookupValueName = product.PurchaseUnit;
                var purchaseUnit = await this.CommonLookupValuesAsync(lookupModel);
                singleProduct.PurchaseUnit = purchaseUnit.LookupValueId;

                lookupModel.Name = "PharmacyGst";
                lookupModel.LookupValueName = product.Gst;
                var gst = await this.CommonLookupValuesAsync(lookupModel);
                singleProduct.TaxId = gst.LookupValueId;
                singleProduct.Tax = product.Gst;

                singleProduct.PurchaseUnitQty = string.IsNullOrEmpty(product.PurchaseQuantity) ? 1 : int.Parse(product.PurchaseQuantity);
                singleProduct.SaleUnitQty = string.IsNullOrEmpty(product.SaleQuantity) ? 1 : int.Parse(product.SaleQuantity);
                singleProduct.ProductName = product.ProductName;
                singleProduct.GenericName = product.GenericName;
                singleProduct.Barcode = product.BarCode;
                singleProduct.ExpiryDate =Convert.ToDateTime(product.ExpiryDate);
                singleProduct.IsBatchNumber = !string.IsNullOrEmpty(product.BatchNumberRequired) && product.BatchNumberRequired.Equals("y", StringComparison.CurrentCultureIgnoreCase);
                singleProduct.IsProductExpire = !string.IsNullOrEmpty(product.ProductExpire) && product.ProductExpire.Equals("y", StringComparison.CurrentCultureIgnoreCase);
                singleProduct.CreatedBy = model.CreatedBy;
                singleProduct.SupplierId = (int?)null;
                singleProduct.HSNCode = !string.IsNullOrEmpty(product.HSNCode) ? product.HSNCode.Trim() : null;
                try
                {
                    singleProduct.IsGetProductId = true;
                    singleProduct.PharmacyProductId = await this.pharmacyService.CreatePharmacyProduct(singleProduct);
                    
                    singleProduct.BatchNumber = product.BatchNumber;
                    if (singleProduct.PharmacyProductId < 0)
                    {
                        singleProduct.PharmacyProductId *= -1;
                    }
                    else
                    {
                        singleProduct.IsGetProductId = false;
                    }
                }
                catch (Exception)
                {
                    continue;
                }
                finally
                {
                    singleProduct.BillNumber = product.BillNumber;
                    totalProductList.Add(singleProduct);
                }
            }

            return totalProductList;
        }

        /// <summary>
        /// Commons the lookup values asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        private async Task<LookupValueModel> CommonLookupValuesAsync(LookupValueModel model)
        {
            var allCategory = await this.pharmacyService.FetchLookupValues(new LookupValueModel { LookupValueName = model.LookupValueName, Name = model.Name });
            var checkCategoryExists = allCategory?.ToList().Find(
            m => string.Equals(m.Name, model.LookupValueName, StringComparison.CurrentCultureIgnoreCase));
            if (checkCategoryExists == null)
            {
                var newCategory = new LookupValueModel
                {
                    LookupId = 0,
                    Name = model.LookupValueName,
                    CreatedBy = model.CreatedBy
                };

                switch (model.Name)
                {
                    case "PharmacyCategory":
                        newCategory.LookupValueId = await this.pharmacyService.CreateCategoryAsync(newCategory);
                        break;
                    case "PharmacyUnit":
                        newCategory.LookupValueId = await this.pharmacyService.CreateUnitAsync(newCategory);
                        break;
                    case "PharmacyRack":
                        newCategory.LookupValueId = await this.pharmacyService.CreateRackAsync(newCategory);
                        break;
                    case "PharmacyGst":
                        newCategory.LookupValueId = await this.pharmacyService.CreateGstAsync(newCategory);
                        break;
                }

                return newCategory;
            }
            else
            {
                return checkCategoryExists;
            }
        }

        /// <summary>
        /// Adds the purchase bill from excel.
        /// </summary>
        /// <param name="products">The products.</param>
        /// <param name="bills">The bills.</param>
        /// <returns></returns>
        private async Task<int> AddPurchaseBillFromExcel(List<ProductModel> products, RawPurchaseBillModel bills)
        {
            var purchaseBillModel = new PurchaseBillHeaderModel
            {
                Products = new List<PurchaseBillDetailModel>()
            };

            foreach (var bill in bills.Products)
            {
                var detailModel = new PurchaseBillDetailModel();
                var findProduct = products.Find(m => string.Equals(m.ProductName, bill.ProductName, StringComparison.CurrentCultureIgnoreCase));
                if (findProduct == null)
                {
                    break;
                }

                detailModel.PharmacyProductId = findProduct.PharmacyProductId;
                detailModel.TaxId = findProduct.TaxId;
                detailModel.TaxPercentage = findProduct.Tax;
                detailModel.TaxPerItem = Convert.ToInt32(findProduct.Tax);
                detailModel.Mrp = Convert.ToDouble(bill.Mrp);
                detailModel.PurchaseRate = Convert.ToDouble(bill.PurchaseRate);
                detailModel.Barcode = bill.BarCode;
                detailModel.BatchNumber = bill.BatchNumber;
                detailModel.ExpiryDate = findProduct.IsExpiry ? Convert.ToDateTime(bill.ExpiryDate) : (DateTime?)null;
                detailModel.Free = !string.IsNullOrEmpty(bill.Free) ? Convert.ToInt32(bill.Free) : 0;
                detailModel.Quantity = Convert.ToInt32(bill.Quantity);
                detailModel.IsExpiry = findProduct.IsExpiry;
                detailModel.Total = Math.Round(detailModel.Quantity * detailModel.PurchaseRate, 2);
                detailModel.DiscountAmount = 0; detailModel.DiscountPerItem = 0;
                detailModel.TaxAmount = Math.Round((detailModel.Total * Convert.ToInt32(detailModel.TaxPercentage)) / 100, 2);
                detailModel.NetAmount = Math.Round(detailModel.Total + detailModel.TaxAmount, 2);
                detailModel.GSTType = bill.GSTType;
                purchaseBillModel.Products.Add(detailModel);

                purchaseBillModel.BillAmount += detailModel.Total;
                purchaseBillModel.Taxes += detailModel.TaxAmount;
                purchaseBillModel.NetAmount += detailModel.NetAmount;
            }

            purchaseBillModel.BillNumber = bills.BillNumber;
            purchaseBillModel.PharmacyWareHouseId = Convert.ToInt32(bills.PharmacyWareHouseId);
            purchaseBillModel.Discount = 0;
            purchaseBillModel.BillType = "Cash";
            purchaseBillModel.BillAmount = Math.Round(purchaseBillModel.BillAmount, 2);
            purchaseBillModel.Taxes = Math.Round(purchaseBillModel.Taxes, 2);
            purchaseBillModel.NetAmount = Math.Round(purchaseBillModel.NetAmount, 2);
            purchaseBillModel.BillDate = DateTime.Now;
            purchaseBillModel.CreatedBy = bills.CreatedBy;
            var getSupplier = await this.supplierService.FetchAsync(new SupplierModel { SupplierOf = "pharmacy", Name = bills.SupplierName });

            if (getSupplier == null)
            {
                purchaseBillModel.SupplierId = await this.supplierService.InsertSupplierAsync(new SupplierModel { Name = bills.SupplierName, City = "Hyderabad", Address = "Hyderabad", SupplierOf = "pharmacy" });
            }
            else
            {
                purchaseBillModel.SupplierId = getSupplier.SupplierId;
            }

            return await this.pharmacyService.AddNewPurchaseBill(purchaseBillModel);
        }
    }
}
