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

    using Domain.Services;

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

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

    using Utilities;
    using Shared.UserModels.Common;
    using Shared.UserModels.Inventory;
    using Hims.Api.Models;
    using System.Collections.Generic;

    /// <summary>
    /// The inventory controller.
    /// </summary>
    [Authorize]
    [Route("api/inventory")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class InventoryController : BaseController
    {
        /// <summary>
        /// The inventory service.
        /// </summary>
        private readonly IInventoryService inventoryService;

        /// <summary>
        /// The Inventory log services.
        /// </summary>
        private readonly IInventoryLogService inventoryLogServices;

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

        /// <inheritdoc />
        public InventoryController(
            IInventoryService inventoryService,
            IInventoryLogService inventoryLogServices,
            ICompanyService companyService)
        {
            this.inventoryService = inventoryService;
            this.inventoryLogServices = inventoryLogServices;
            this.companyService = companyService;
        }

        /// <summary>
        /// The insert inventory units async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("create-unit")]
        public async Task<ActionResult> InsertInventoryUnitsAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.CreateUnitAsync(model);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.Units,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Unit <b>'{model.Name}'</b> <b>Added</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// The insert inventory category async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("create-category")]
        public async Task<ActionResult> InsertInventoryCategoryAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.CreateCategoryAsync(model);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.Categories,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Category <b>'{model.Name}'</b> <b>Added</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }

            }
            return this.Success(response);
        }

        /// <summary>
        /// The insert inventory rack async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("create-rack")]
        public async Task<ActionResult> InsertInventoryRackAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.CreateRackAsync(model);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.Racks,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Rack <b>'{model.Name}'</b> <b>Added</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }

            }

            return this.Success(response);
        }

        /// <summary>
        /// The insert inventory gst async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("create-gst")]
        public async Task<ActionResult> InsertInventoryGstAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.CreateGstAsync(model);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.GST,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New GST <b>'{model.Name}%'</b> <b>Added</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }

            }
            return this.Success(response);
        }

        /// <summary>
        /// The add inventory product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-product")]
        public async Task<ActionResult> AddInventoryProductAsync([FromBody] ProductModel model)
        {
            model = (ProductModel)EmptyFilter.Handler(model);
            var checkAlreadyExists = await this.inventoryService.CheckProductAlreadyAlreadyExists(model.ProductName);
            if (checkAlreadyExists > 0)
            {
                return this.Success(-1);
            }
            var checkProduct = await this.CheckProducts(model);
            var response = await this.inventoryService.CreateInventoryProduct(checkProduct);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.Products,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"New Product <b>'{model.ProductName}'</b> <b>Added</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// The update inventory product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [Route("update-product")]
        public async Task<ActionResult> UpdateInventoryProductAsync([FromBody] ProductModel model)
        {
            model = (ProductModel)EmptyFilter.Handler(model);
            var checkProduct = await this.CheckProducts(model);
            var response = await this.inventoryService.UpdateInventoryProduct(checkProduct);
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = (int)InventoryLogTypes.Products,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"Product <b>'{model.ProductName}'</b> <b>Updated</b> Successfully"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }
            }
            return this.Success(response);
        }

        /// <summary>
        /// The update inventory product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("delete-product")]
        public async Task<ActionResult> DeleteInventoryProductAsync([FromBody] ProductModel model)
        {
            model = (ProductModel)EmptyFilter.Handler(model);
            try
            {
                var response = await this.inventoryService.DeleteInventoryProduct(model.InventoryProductId);
                if (response > 0)
                {
                    try
                    {
                        var iLogs = new InventoryLogModel
                        {
                            AccountId = model.LoginAccountId,
                            InventoryLogTypeId = (int)InventoryLogTypes.Products,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LogDescription = $@"Product <b>'{model.ProductName}'</b> <b>Deleted</b> Successfully"
                        };
                        await this.inventoryLogServices.LogAsync(iLogs);
                    }
                    catch (Exception e)
                    {
                        //logs
                    }

                }
                return this.Success(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning
                });
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("update or delete on table \"InventoryProduct\" violates foreign key constraint \"InventoryPurchaseDetail_InventoryProductId_fkey\" on table \"InventoryPurchaseDetail\""))
                {
                    return this.Success(new GenericResponse
                    {
                        Status = GenericStatus.Error,
                        Message = ex.Message
                    });
                }
                throw;
            }
        }

        /// <summary>
        /// The fetch inventory product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-product")]
        public async Task<ActionResult> FetchInventoryProductAsync([FromBody] ProductModel model)
        {
            var models = model ?? new ProductModel();
            var response = await this.inventoryService.FetchInventoryProduct(models);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch lookup value async.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-lookup-value")]
        public async Task<ActionResult> FetchLookupValueAsync(LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            if (string.IsNullOrEmpty(model.Name))
            {
                return this.BadRequest("Invalid name.");
            }

            var response = await this.inventoryService.FetchLookupValues(model);
            return this.Success(response);
        }

        /// <summary>
        /// The update lookup value async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("update-lookup-value")]
        public async Task<ActionResult> UpdateLookupValueAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.UpdateLookupValueAsync(model);
            if (response < 0)
            {
                return this.BadRequest("The given value already exists.");
            }
            int inventoryLogTypeId;
            string logDescription;
            switch (model.TypeOf)
            {
                case "Gst":
                    inventoryLogTypeId = (int)InventoryLogTypes.GST;
                    logDescription = $@"GST <b>'{model.Name}%'</b> <b>Updated</b> Successfully.";
                    break;
                case "Unit":
                    inventoryLogTypeId = (int)InventoryLogTypes.Units;
                    logDescription = $@"Unit <b>'{model.Name}'</b> <b>Updated</b> Successfully.";
                    break;
                case "Category":
                    inventoryLogTypeId = (int)InventoryLogTypes.Categories;
                    logDescription = $@"Category <b>'{model.Name}'</b> <b>Updated</b> Successfully.";
                    break;
                case "Rack":
                    inventoryLogTypeId = (int)InventoryLogTypes.Racks;
                    logDescription = $@"Rack <b>'{model.Name}'</b> Updated Successfully.";
                    break;
                default:
                    return this.BadRequest("No Category matched");
            }

            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.LoginAccountId,
                        InventoryLogTypeId = inventoryLogTypeId,
                        LogFrom = (short)model.LoginRoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = logDescription
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }

            }
            return this.Success(response);
        }

        /// <summary>
        /// The delete lookup value async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("delete-lookup-value")]
        public async Task<ActionResult> DeleteLookupValueAsync([FromBody] LookupValueModel model)
        {
            model = (LookupValueModel)EmptyFilter.Handler(model);
            try
            {
                var response = await this.inventoryService.DeleteLookupValueAsync(model.LookupValueId);

                int inventoryLogTypeId;
                string logDescription;
                switch (model.TypeOf)
                {
                    case "Gst":
                        inventoryLogTypeId = (int)InventoryLogTypes.GST;
                        logDescription = $@"GST <b>'{model.Name}%'</b> <b>Deleted</b> Successfully.";
                        break;
                    case "Unit":
                        inventoryLogTypeId = (int)InventoryLogTypes.Units;
                        logDescription = $@"Unit <b>'{model.Name}'</b> <b>Deleted</b> Successfully.";
                        break;
                    case "Category":
                        inventoryLogTypeId = (int)InventoryLogTypes.Categories;
                        logDescription = $@"Category <b>'{model.Name}'</b> <b>Deleted</b> Successfully.";
                        break;
                    case "Rack":
                        inventoryLogTypeId = (int)InventoryLogTypes.Racks;
                        logDescription = $@"Rack <b>'{model.Name}'</b> <b>Deleted</b> Successfully.";
                        break;
                    default:
                        return this.BadRequest("No Category matched");
                }

                if (response > 0)
                {
                    try
                    {
                        var iLogs = new InventoryLogModel
                        {
                            AccountId = model.LoginAccountId,
                            InventoryLogTypeId = inventoryLogTypeId,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LogDescription = logDescription
                        };
                        await this.inventoryLogServices.LogAsync(iLogs);
                    }
                    catch (Exception e)
                    {
                        //logs
                    }
                }
                return this.Success(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning
                });
            }
            catch (Exception ex)
            {
                if (model.TypeOf == "Rack")
                {
                    if (ex.Message.Contains("update or delete on table \"LookupValue\" violates foreign key constraint \"InventoryProduct_RackId_fkey\" on table \"InventoryProduct\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }
                if (model.TypeOf == "Category")
                {
                    if (ex.Message.Contains("update or delete on table \"LookupValue\" violates foreign key constraint \"InventoryProduct_CategoryId_fkey\" on table \"InventoryProduct\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }

                if (model.TypeOf == "Unit")
                {
                    if (ex.Message.Contains("update or delete on table \"LookupValue\" violates foreign key constraint \"InventoryProduct_PurchaseUnit_fkey\" on table \"InventoryProduct\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }
                if (model.TypeOf == "Gst")
                {
                    if (ex.Message.Contains("update or delete on table \"LookupValue\" violates foreign key constraint \"InventoryProduct_TaxId_fkey\" on table \"InventoryProduct\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }
                throw;
            }
        }

        /// <summary>
        /// The add purchase bill async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-purchase-bill")]
        public async Task<ActionResult> AddPurchaseBillAsync([FromBody] InventoryPurchaseBillModel model)
        {
            model = (InventoryPurchaseBillModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.AddPurchaseBillAsync(model);
            if (response == -10)
            {
                return this.Success(response);
            }
            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.CreatedBy,
                        InventoryLogTypeId = (int)InventoryLogTypes.Purchase,
                        LogFrom = (short)model.RoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"{model.CreatedByName} has Added Purchase Bill with BillNo: <b>{model.BillNumber}</b> "
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }
            }
            return response > 0 ? this.Success(response) : this.ServerError();
        }

        /// <summary>
        /// The fetch added purchase bill async.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <param name="billNumber">
        /// The bill number.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-added-purchase-bill")]
        public async Task<ActionResult> FetchAddedPurchaseBillAsync(int? id, string billNumber)
        {
            if (id == null && string.IsNullOrEmpty(billNumber))
            {
                return this.BadRequest();
            }

            var response = await this.inventoryService.FetchAddedPurchaseBillAsync(id, billNumber);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch inventory stock async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-inventory-stock")]
        public async Task<ActionResult> FetchInventoryStockAsync([FromBody] InventoryStockModel model)
        {
            var models = model ?? new InventoryStockModel();
            var response = await this.inventoryService.FetchInventoryStocks(models);
            return this.Success(response);
        }

        /// <summary>
        /// The update inventory stock async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("update-inventory-stock")]
        public async Task<ActionResult> UpdateInventoryStockAsync([FromBody] InventoryStockModel model)
        {
            var models = model ?? new InventoryStockModel();
            var record = await this.inventoryService.UpdateInventoryStocks(models);
            var iLogs = new InventoryLogModel
            {
                AccountId = model.ModifiedBy,
                InventoryLogTypeId = (int)InventoryLogTypes.Stock,
                LogFrom = (short)model.LoginRoleId,
                LogDate = DateTime.UtcNow.AddMinutes(330),
                LogDescription = $@"{model.ModifiedName} Updated for category: <b>'{model.CategoryName}'</b> and Product:<b>'{model.ProductName}'</b> As Batch No.<b>'{model.BatchNumber}'</b> Expiry Date: <b>'{model.ExpiryDate?.ToString("MM/dd/yyyy")}'</b> Successfully"
            };
            await this.inventoryLogServices.LogAsync(iLogs);
            return this.Success(record);
        }

        /// <summary>
        /// The fetch return bill number async.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-return-bill-number")]
        public async Task<ActionResult> FetchReturnBillNumberAsync()
        {
            var response = await this.inventoryService.FetchBillNumber();
            return this.Success(response);
        }

        /// <summary>
        /// The add return purchase bill async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add-return-purchase-bill")]
        public async Task<ActionResult> AddReturnPurchaseBillAsync([FromBody] InventoryPurchaseReturnModel model)
        {
            model = (InventoryPurchaseReturnModel)EmptyFilter.Handler(model);
            var response = await this.inventoryService.AddReturnPurchaseBillAsync(model);

            if (response > 0)
            {
                try
                {
                    var iLogs = new InventoryLogModel
                    {
                        AccountId = model.CreatedBy,
                        InventoryLogTypeId = (int)InventoryLogTypes.Return,
                        LogFrom = (short)model.RoleId,
                        LogDate = DateTime.UtcNow.AddMinutes(330),
                        LogDescription = $@"{model.CreatedByName} has Returned the products with BillNo: <b>{model.BillNumber}</b>"
                    };
                    await this.inventoryLogServices.LogAsync(iLogs);
                }
                catch (Exception e)
                {
                    //logs
                }
            }

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

        /// <summary>
        /// The fetch added purchase return bill async.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-added-purchase-return-bill")]
        public async Task<ActionResult> FetchAddedPurchaseReturnBillAsync(string id)
        {
            if (string.IsNullOrEmpty(id))
            {
                return this.BadRequest();
            }

            var response = await this.inventoryService.FetchAddedReturnPurchaseBillAsync(Convert.ToInt32(id));
            return this.Success(response);
        }

        /// <summary>
        /// The fetch dashboard reorder level.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-dashboard-reorder")]
        public async Task<ActionResult> FetchDashboardReorderLevel()
        {
            var response = await this.inventoryService.FetchDashboardReorderLevel();
            return this.Success(response);
        }

        /// <summary>
        /// The fetch dashboard expiry item.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-dashboard-expiry")]
        public async Task<ActionResult> FetchDashboardExpiryItem()
        {
            var response = await this.inventoryService.FetchDashboardExpiryItem();
            return this.Success(response);
        }

        /// <summary>
        /// The fetch dashboard next month expiry item.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-dashboard-expiry-next-month")]
        public async Task<ActionResult> FetchDashboardNextMonthExpiryItem()
        {
            var response = await this.inventoryService.FetchDashboardNextMonthExpiryItem();
            return this.Success(response);
        }

        /// <summary>
        /// The fetch dashboard current month expiry item.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-dashboard-expire-current-month")]
        public async Task<ActionResult> FetchDashboardCurrentMonthExpiryItem()
        {
            var response = await this.inventoryService.FetchDashboardCurrentMonthExpireItem();
            var list = response.ToList();

            foreach (var item in list)
            {
                if (item.ExpiryDate == null)
                {
                    continue;
                }

                var currentDate = DateTime.Now;
                var expireDate = (DateTime)item.ExpiryDate;
                if ((currentDate.Year == expireDate.Year) && (currentDate.Month == expireDate.Month))
                {
                    item.DaysToExpire = expireDate.Day - currentDate.Day;
                }
            }

            return this.Success(list);
        }

        /// <summary>
        /// The fetch pharmacy products.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-products")]
        public async Task<ActionResult> FetchPharmacyProducts()
        {
            var response = await this.inventoryService.FetchInventoryProducts();
            return this.Success(response);
        }

        /// <summary>
        /// The fetch pharmacy purchase bill.
        /// </summary>
        /// <param name="billNumber"></param>
        /// <param name="type">
        /// The type.
        /// </param>       
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpGet]
        [Route("fetch-bills")]
        public async Task<ActionResult> FetchInventoryBill(string billNumber, string type)
        {
            if (type == "P")//
            {

                var response = await this.inventoryService.FetchAddedPurchaseBillAsync(null, billNumber);
                return this.Success(response);

            }
            else
            {
                var response = await this.inventoryService.FetchInventoryReturnBill(billNumber);
                return this.Success(response);
            }
        }

        /// <summary>
        /// Fetches the purchase bill asynchronous.
        /// </summary>
        /// <param name="supplierId">The supplier identifier.</param>
        /// <param name="inventoryPurchaseHeaderid">The inventory purchase headerid.</param>
        /// <param name="billNumber">The bill number.</param>
        /// <param name="header">The header.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-inventory-purchase-bill")]
        public async Task<ActionResult> FetchPurchaseBillAsync(int? supplierId, int? inventoryPurchaseHeaderid, string billNumber, [FromHeader] LocationHeader header)
        {
            if (supplierId == null && inventoryPurchaseHeaderid == null && string.IsNullOrEmpty(billNumber))
            {
                return this.BadRequest("No parameter passed");
            }

            var locationId = header != null && !string.IsNullOrEmpty(header.LocationId) ? Convert.ToInt32(header.LocationId) : (int?)null;

            var response = await this.inventoryService.FetchPurchaseBill(supplierId, inventoryPurchaseHeaderid, billNumber, locationId);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the new purchase bill asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="header"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-new-purchase-bill")]
        public async Task<ActionResult> AddNewPurchaseBillAsync([FromBody] InventoryBillHeaderModel model, [FromHeader] LocationHeader header)
        {
            model = (InventoryBillHeaderModel)EmptyFilter.Handler(model);
            model.LocationId = header != null && !string.IsNullOrEmpty(header.LocationId) ? Convert.ToInt32(header.LocationId) : (int?)null;
            var response = await this.inventoryService.AddInventoryPurchaseBillAsync(model);

            switch (response)
            {
                case -1:
                case -4:
                    return this.BadRequest("Error occured while adding purchase bill.");
                case -3:
                    return this.BadRequest("Error occured while creating inventory stock.");
                default:
                    if (response > 0)
                    {
                        try
                        {
                            var iLogs = new InventoryLogModel
                            {
                                AccountId = model.CreatedBy,
                                InventoryLogTypeId = (int)InventoryLogTypes.Purchase,
                                LogFrom = (short)model.LoginRoleId,
                                LogDate = DateTime.UtcNow.AddMinutes(330),
                                LogDescription = $@"{model.CreatedByName} has {(model.InventoryPurchaseHeaderId > 0 ? "Updated" : "Added")} Purchase Bill with BillNo: <b>{model.BillNumber}</b> "
                            };
                            await this.inventoryLogServices.LogAsync(iLogs);
                        }
                        catch (Exception e)
                        {
                            //logs
                        }
                    }
                    return this.Success(response);
            }
        }

        /// <summary>
        /// Fetches the existing batch numbers.
        /// </summary>
        /// <param name="inventoryProductId">The inventory product identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        [Route("get-batch-numbers")]
        public async Task<ActionResult> FetchExistingBatchNumbers(int inventoryProductId)
        {
            var response = await this.inventoryService.FetchExistingBatchNumbers(inventoryProductId, (int?)null);
            return this.Success(response ?? new List<string>());
        }

        /// <summary>
        /// Deletes the purchase bill product asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="header">The header.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("delete-purchase-bill-product")]
        public async Task<ActionResult> DeletePurchaseBillProductAsync([FromBody] InventoryBillHeaderModel model, [FromHeader] LocationHeader header)
        {
            model = (InventoryBillHeaderModel)EmptyFilter.Handler(model);
            model.LocationId = header != null && !string.IsNullOrEmpty(header.LocationId) ? Convert.ToInt32(header.LocationId) : (int?)null;
            var response = await this.inventoryService.DeletePurchaseBillItemAsync(model);

            switch (response)
            {
                case -1:
                case -4:
                    return this.BadRequest("Error occured while adding purchase bill.");
                case -3:
                    return this.BadRequest("Error occured while creating inventory stock.");
                default:
                    if (response > 0)
                    {
                        try
                        {
                            var iLogs = new InventoryLogModel
                            {
                                AccountId = model.CreatedBy,
                                InventoryLogTypeId = (int)InventoryLogTypes.Purchase,
                                LogFrom = (short)model.LoginRoleId,
                                LogDate = DateTime.UtcNow.AddMinutes(330),
                                LogDescription = $@"{model.CreatedByName} has {(model.InventoryPurchaseHeaderId > 0 ? "Updated" : "Added")} Purchase Bill with BillNo: <b>{model.BillNumber}</b> "
                            };
                            await this.inventoryLogServices.LogAsync(iLogs);
                        }
                        catch (Exception e)
                        {
                            //logs
                        }
                    }
                    return this.Success(response);
            }
        }

        /// <summary>
        /// Checks the products.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        private async Task<ProductModel> CheckProducts(ProductModel model)
        {
            if (model.CompanyId == 0)
            {
                var checkCompanyExits = await this.companyService.FetchAsync(new CompanyModel { TypeOf = "inventoryCompany", Name = model.CompanyName });
                if (checkCompanyExits == null)
                {
                    var newCompany = new CompanyModel
                    {
                        Name = model.CompanyName,
                        TypeOf = "inventoryCompany",
                        Location = "Hyderabad"
                    };

                    newCompany.CompanyId = await this.companyService.InsertCompanyAsync(newCompany);
                    model.CompanyId = newCompany.CompanyId;
                }
                else
                {
                    model.CompanyId = checkCompanyExits.CompanyId;
                }
            }

            LookupValueModel lookupModel = new LookupValueModel();

            if (model.CategoryId == 0)
            {
                lookupModel.Name = "InventoryCategory";
                lookupModel.LookupValueName = model.CategoryName;
                var category = await this.CommonLookupValuesAsync(lookupModel);
                model.CategoryId = category.LookupValueId;
            }

            if (model.TaxId == 0)
            {
                lookupModel.Name = "InventoryGst";
                lookupModel.LookupValueName = model.Tax;
                var gst = await this.CommonLookupValuesAsync(lookupModel);
                model.TaxId = gst.LookupValueId;
            }

            if (model.PurchaseUnit == 0)
            {
                lookupModel.Name = "InventoryUnit";
                lookupModel.LookupValueName = model.PurchaseUnitName;
                var purchaseUnit = await this.CommonLookupValuesAsync(lookupModel);
                model.PurchaseUnit = purchaseUnit.LookupValueId;
            }

            return model;
        }

        /// <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.inventoryService.FetchLookupValues(model);
            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
                };

                switch (model.Name)
                {
                    case "InventoryCategory":
                        newCategory.LookupValueId = await this.inventoryService.CreateCategoryAsync(newCategory);
                        break;
                    case "InventoryUnit":
                        newCategory.LookupValueId = await this.inventoryService.CreateUnitAsync(newCategory);
                        break;
                    case "InventoryRack":
                        newCategory.LookupValueId = await this.inventoryService.CreateRackAsync(newCategory);
                        break;
                    case "InventoryGst":
                        newCategory.LookupValueId = await this.inventoryService.CreateGstAsync(newCategory);
                        break;
                }

                return newCategory;
            }
            else
            {
                return checkCategoryExists;
            }
        }
    }
}
