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

    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Domain.Configurations;
    using Hims.Domain.Helpers;
    using Hims.Shared.UserModels.Common;
    using Hims.Shared.UserModels.Vendors;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using Models.Provider;
    using Npgsql;
    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.Library.Enums;
    using Shared.UserModels;
    using Utilities;

    /// <inheritdoc />
    [Route("api/supplier")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class SuppliersController : BaseController
    {
        /// <summary>
        /// The supplier service.
        /// </summary>
        private readonly ISupplierService supplierService;

        /// <summary>
        /// The pharmacy log service.
        /// </summary>
        private readonly IPharmacyLogService pharmacyLogService;

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

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

        /// <summary>
        /// The FTP upload helper.
        /// </summary>
        private readonly IFtpUploadHelper ftpUploadHelper;

        /// <inheritdoc />
        public SuppliersController(ISupplierService supplierService, IPharmacyLogService pharmacyLogService, IInventoryLogService inventoryLogServices, IRunningEnvironment runningEnvironment, IFtpUploadHelper ftpUploadHelper)
        {
            this.supplierService = supplierService;
            this.pharmacyLogService = pharmacyLogService;
            this.inventoryLogServices = inventoryLogServices;
            this.runningEnvironment = runningEnvironment;
            this.ftpUploadHelper = ftpUploadHelper;
        }

        /// <summary>
        /// The create supplier async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("add")]
        public async Task<ActionResult> CreateSupplierAsync([FromBody] SupplierModel model, [FromHeader] LocationHeader location)
        {
            model = (SupplierModel)EmptyFilter.Handler(model);
            var response = await this.supplierService.InsertSupplierAsync(model);
           
            try
            {
                if (response > 0)
                {
                    if (model.IsCreateAccount)
                    {
                        await this.supplierService.AddSuplierAccountAsync(new SupplierModel { SupplierId = response, CreatedBy = model.CreatedBy, LocationId = Convert.ToInt32(location.LocationId) });
                    }
                    if (model.SupplierOf == "pharmacy")
                    {
                        var pharmacyLogModel = new PharmacyLogModel
                        {
                            AccountId = model.LoginAccountId,
                            PharmacyLogTypeId = (int)PharmacyLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow,
                            LogDescription = $@"{model.CreatedByName} has  <b>Added</b> the New Vendor '{model.Name}' Successfully."
                        };
                        await this.pharmacyLogService.LogAsync(pharmacyLogModel);
                    }
                    else
                    {

                        var iLogs = new InventoryLogModel
                        {
                            AccountId = model.LoginAccountId,
                            InventoryLogTypeId = (int)InventoryLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LogDescription = $@" {model.CreatedByName} has  <b>Added</b> the New Vendor <b>'{model.Name}'</b>  Successfully."
                        };
                        await this.inventoryLogServices.LogAsync(iLogs);

                    }
                }
            }
            catch (Exception)
            {
                //logs
            }

            return this.Success(response);
        }

        /// <summary>
        /// The fetch supplier async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch")]
        public async Task<ActionResult> FetchSupplierAsync([FromBody] SupplierModel model)
        {
            model = (SupplierModel)EmptyFilter.Handler(model);
            var response = await this.supplierService.FetchAllAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The update supplier async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [Route("update")]
        public async Task<ActionResult> UpdateSupplierAsync([FromBody] SupplierModel model)
        {
            model = (SupplierModel)EmptyFilter.Handler(model);
            var response = await this.supplierService.UpdateSupplierAsync(model);

            try
            {
                if (response > 0)
                {
                    if (model.SupplierOf == "pharmacy")
                    {
                        var pharmacyLogModel = new PharmacyLogModel
                        {
                            AccountId = model.LoginAccountId,
                            PharmacyLogTypeId = (int)PharmacyLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow,
                            LogDescription = $@"{model.CreatedByName} has Updated the Vendor '{model.Name}' Details Successfully."
                        };
                        await this.pharmacyLogService.LogAsync(pharmacyLogModel);
                    }
                    else
                    {

                        var iLogs = new InventoryLogModel
                        {
                            AccountId = model.LoginAccountId,
                            InventoryLogTypeId = (int)InventoryLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LogDescription = $@" {model.CreatedByName} has Updated the Vendor <b>'{model.Name}' Details </b> Successfully."
                        };
                        await this.inventoryLogServices.LogAsync(iLogs);
                    }
                }
            }
            catch (Exception)
            {
                //logs
            }
            return this.Success(response);
        }

        /// <summary>
        /// The delete supplier async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("delete")]
        public async Task<ActionResult> DeleteSupplierAsync([FromBody] SupplierModel model)
        {
            model = (SupplierModel)EmptyFilter.Handler(model);
            try
            {
                var response = await this.supplierService.DeleteSupplierAsync(model.SupplierId);

                try
                {
                    if (model.SupplierOf == "pharmacy")
                    {
                        var pharmacyLogModel = new PharmacyLogModel
                        {
                            AccountId = model.LoginAccountId,
                            PharmacyLogTypeId = (int)PharmacyLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow,
                            LogDescription = $@"Vendor '{model.Name}' Deleted Successfully."
                        };        
                        await this.pharmacyLogService.LogAsync(pharmacyLogModel);
                    }
                    else
                    {
                        var iLogs = new InventoryLogModel
                        {
                            AccountId = model.LoginAccountId,
                            InventoryLogTypeId = (int)InventoryLogTypes.Vendor,
                            LogFrom = (short)model.LoginRoleId,
                            LogDate = DateTime.UtcNow.AddMinutes(330),
                            LogDescription = $@"Vendor <b>'{model.Name}' Deleted </b>Successfully."
                        };
                        await this.inventoryLogServices.LogAsync(iLogs);
                    }
                }
                catch (Exception)
                {

                }
                return this.Success(new GenericResponse
                {
                    Status = response > 0 ? GenericStatus.Success : GenericStatus.Warning
                });
            }
            catch (Exception ex)
            {
                if (model.SupplierOf == "inventory")
                {
                    if (ex.Message.Contains("update or delete on table \"Supplier\" violates foreign key constraint \"InventoryPurchaseHeader_SupplierId_fkey\" on table \"InventoryPurchaseHeader\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }
                if (model.SupplierOf == "pharmacy")
                {
                    if (ex.Message.Contains("update or delete on table \"Supplier\" violates foreign key constraint \"PharmacyPurchaseHeader_SupplierId_fkey\" on table \"PharmacyPurchaseHeader\""))
                    {
                        return this.Success(new GenericResponse
                        {
                            Status = GenericStatus.Error,
                            Message = ex.Message
                        });
                    }
                }
                throw;

            }
        }

        /// <summary>
        /// The modify supplier product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("modify-supplier-product")]
        public async Task<ActionResult> ModifySupplierProductAsync([FromBody] SupplierProductModel model)
        {
            model = (SupplierProductModel)EmptyFilter.Handler(model);
            var response = await this.supplierService.AddSupplierProductAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// The fetch supplier product async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch-supplier-product")]
        public async Task<ActionResult> FetchSupplierProductsAsync([FromBody] ProductModel model)
        {
            model = (ProductModel)EmptyFilter.Handler(model);
            var response = await this.supplierService.FetchSupplierPharmacyProduct(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the suppliers account asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <param name="location">The location.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-supplier-account")]
        public async Task<ActionResult> AddSuppliersAccountAsync([FromBody] SupplierModel model, [FromHeader] LocationHeader location)
        {
            model = (SupplierModel)EmptyFilter.Handler(model);
            model.LocationId = Convert.ToInt32(location.LocationId);
            var response = await this.supplierService.AddSuplierAccountAsync(model);
            return this.Success(response);
        }

        /// <summary>
        /// Adds the supplier product rate list asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Route("add-supplier-rate-list")]
        [Consumes("multipart/form-data")]
        public async Task<ActionResult> AddSupplierProductRateListAsync([FromForm] SupplierNewProductModel model, [FromHeader] LocationHeader location)
        {
            model = (SupplierNewProductModel)EmptyFilter.Handler(model);
            var checkIf= await this.supplierService.CheckIfDateRangeAlreadyExists(model);
            if(checkIf > 0)
            {
                return this.BadRequest("This date range already exists.");
            }
                        
            var valueProd = Newtonsoft.Json.JsonConvert.DeserializeObject<List<SupplierProductDetailModel>>(model.StringifiedProducts);
            if(valueProd.Count == 0)
            {
                return this.BadRequest("Invalid products supplied.");
            }
            model.Products = valueProd;

            var files = this.Request.Form.Files;
            if (files.Count > 0)
            {
                #region FTP
                var filePath = $@"{this.runningEnvironment.CurrentEnvironment}/SupplierRateDocument/{model.SupplierId}";
                await this.ftpUploadHelper.CreateDirectory(filePath);
                var dbPath = $@"{DateTime.UtcNow.Ticks}{Path.GetExtension(files[0].FileName)}";
                filePath += $@"/{dbPath}";
                var uploadResponse = await this.ftpUploadHelper.UploadFromFileAsync(filePath, files[0]);
                if (uploadResponse <= 0)
                {
                    return this.BadRequest();
                }
                #endregion
                model.RateCardUrl = $@"{dbPath}";                
            }
            var response = await this.supplierService.AddProductRateListAsync(model);
            if (response>0)
            {
                var pharmacyLogModel = new PharmacyLogModel
                {
                    AccountId = model.LoginAccountId,
                    LogFrom = (short)model.LoginRoleId,
                    PharmacyLogTypeId = (int)PharmacyLogTypes.Vendor,
                    LogDate = DateTime.UtcNow.AddMinutes(330),
                    LogDescription = $"{model.CreatedByName} has Added RateCard - on {DateTime.UtcNow.AddMinutes(330).ToString("MM/dd/yyyy, hh:mm tt")} Successfully",
                    LocationId = Convert.ToInt32(location.LocationId)
                };
                await this.pharmacyLogService.LogAsync(pharmacyLogModel);
            }
            return this.Success(response);
        }

        /// <summary>
        /// Fetches the supplier rate list asynchronous.
        /// </summary>
        /// <param name="supplierId">The supplier identifier.</param>
        /// <returns></returns>
        [HttpGet]
        [Route("fetch-supplier-rate-list")]
        public async Task<ActionResult> FetchSupplierRateListAsync(int supplierId)
        {
            if (supplierId <= 0) { return this.BadRequest("Invalid supplier"); }
            var response = await this.supplierService.FetchRateCardsAsync(supplierId);
            return this.Success(response);
        }
    }
}