using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Mono.TextTemplating;
using Newtonsoft.Json;
using PSTW_CentralSystem.Areas.Inventory.Models;
using PSTW_CentralSystem.DBContext;
using PSTW_CentralSystem.Models;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Reflection;

namespace PSTW_CentralSystem.Controllers.API.Inventory
{
    [ApiController]
    [Route("[controller]")]

    public class InvMainAPI : Controller
    {
        private readonly ILogger<InvMainAPI> _logger;
        private readonly IdentityDBContext _identityDbContext;
        private readonly InventoryDBContext _inventoryDbContext;

        public InvMainAPI(ILogger<InvMainAPI> logger, IdentityDBContext authDbContext, InventoryDBContext inventoryDbContext)
        {
            _logger = logger;
            _identityDbContext = authDbContext;
            _inventoryDbContext = inventoryDbContext;
        }

        public class DepartmentCompany
        {
            public int DepartmentId { get; set; }
            public string? DepartmentName { get; set; }
            public int CompanyId { get; set; }
            public string? CompanyName { get; set; }
        }

        public async Task<List<DepartmentCompany>> GetDepartmentWithCompanyList()
        {
            var departmentList = await _identityDbContext.Departments.ToListAsync();
            var companyList = await _identityDbContext.Companies.ToListAsync();

            // Create a new list to store departments with their company name
            var departmentWithCompanyList = departmentList.Select(department => new DepartmentCompany
            {
                DepartmentId = department.DepartmentId,
                DepartmentName = department.DepartmentName,
                CompanyId = department.CompanyId,
                CompanyName = companyList.FirstOrDefault(company => company.CompanyId == department.CompanyId)?.CompanyName
            }).ToList();

            // Return the constructed list as JSON
            return departmentWithCompanyList;
        }
        public async Task<DepartmentCompany> GetDepartmentWithCompany(int companyId, int departmentId)
        {
            var departmentList = await _identityDbContext.Departments.FirstOrDefaultAsync(d => d.DepartmentId == departmentId );
            var companyList = await _identityDbContext.Companies.FirstOrDefaultAsync(c => c.CompanyId == companyId);

            // Create a new list to store departments with their company name
            var departmentWithCompany = new DepartmentCompany
            {
                DepartmentId = departmentList!.DepartmentId,
                DepartmentName = departmentList.DepartmentName,
                CompanyId = departmentList.CompanyId,
                CompanyName = companyList?.CompanyName
            };

            // Return the constructed list as JSON
            return departmentWithCompany;
        }

        #region Manufacturer

        [HttpPost("ManufacturerList")]
        public async Task<IActionResult> ManufacturerList()
        {
            var manifacturerList = await _inventoryDbContext.Manufacturers.ToListAsync();
            return Json(manifacturerList);
        }

        [HttpPost("AddManufacturer")]
        public async Task<IActionResult> AddManufacturer([FromBody] ManufacturerModel manufacturer)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            if (manufacturer == null)
            {
                return NotFound("Manufacturer is null");
            }

            try
            {
                _inventoryDbContext.Manufacturers.Add(new ManufacturerModel
                {
                    ManufacturerName = manufacturer.ManufacturerName,
                });
                await _identityDbContext.SaveChangesAsync();
                var updatedList = await _inventoryDbContext.Manufacturers.ToListAsync();
                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("DeleteManufacturer/{id}")]
        public async Task<IActionResult> DeleteManufacturer(int id)
        {
            var manufacturer = await _inventoryDbContext.Manufacturers.FindAsync(id);
            if (manufacturer == null)
            {
                return NotFound(new { success = false, message = "Manufacturer not found" });
            }

            _inventoryDbContext.Manufacturers.Remove(manufacturer);
            await _identityDbContext.SaveChangesAsync();

            return Ok(new { success = true, message = "Manufacturer deleted successfully" });
        }

        #endregion Manufacturer

        #region Product

        [HttpPost("ProductList")]
        public async Task<IActionResult> ProductList()
        {
            var productList = await _inventoryDbContext.Products.Include("Manufacturer").ToListAsync();
            return Json(productList);
        }

        [HttpPost("ProductListWithItem")]
        public async Task<IActionResult> ProductListWithItem()
        {
            var productList = await _inventoryDbContext.Products
                .Include(p => p.Items) // Include related items
                .Include(p => p.Manufacturer) // Include related manufacturer
                .ToListAsync();

            return Json(productList);
        }


        [HttpPost("AddProduct")]
        public async Task<IActionResult> AddProduct([FromBody] ProductModel product)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            if (product == null)
            {
                return NotFound("Product is null");
            }

            try
            {
                product.QuantityProduct = 0;
                var productImage = product.ImageProduct; // Save image to wwwroot/media/inventory/images | Images name is product.ModelNo | product.ImageProduct is in base64 string
                if (!string.IsNullOrEmpty(product.ImageProduct))
                {
                    var bytes = Convert.FromBase64String(product.ImageProduct);
                    var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/images", product.ModelNo + ".jpg");
                    await System.IO.File.WriteAllBytesAsync(filePath, bytes);
                    product.ImageProduct = "/media/inventory/images/" + product.ModelNo + ".jpg";
                }
                _inventoryDbContext.Products.Add(product);
                await _identityDbContext.SaveChangesAsync();
                var updatedList = await _inventoryDbContext.Products.Include("Manufacturer").Where(x => x.ManufacturerId == x.ManufacturerId).ToListAsync();
                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("DeleteProduct/{id}")]
        public async Task<IActionResult> DeleteProduct(int id)
        {
            var Product = await _inventoryDbContext.Products.FindAsync(id);
            if (Product == null)
            {
                return NotFound(new { success = false, message = "Product not found" });
            }

            _inventoryDbContext.Products.Remove(Product);
            await _identityDbContext.SaveChangesAsync();

            return Ok(new { success = true, message = "Product deleted successfully" });
        }

        #endregion Product

        #region Company

        [HttpPost("CompanyDepartmentList")]
        public async Task<IActionResult> CompanyDepartmentList()
        {
            var companyList = await _identityDbContext.Companies
                .Include(c => c.Departments)
                .Select(c => new { c.CompanyId, c.CompanyName, Departments = c.Departments
                    .OrderBy(d => d.DepartmentId)
                    .Select(d => new { d.DepartmentId, d.DepartmentName }) 
                })
                .ToListAsync();
            return Json(companyList);
        }

        #endregion Company

        #region Department

        [HttpPost("DepartmentCompanyList")]
        public async Task<IActionResult> DepartmentCompanyList()
        {
            var itemDepartment = await _identityDbContext.Departments
            .Include(d => d.Company) // Include the related Company entity
            .Select(d => new
            {
                d.DepartmentId,
                d.DepartmentName,
                d.CompanyId,
                d.Company.CompanyName,
            })
            .ToListAsync();

            //return Json(await GetDepartmentWithCompanyList());
            return Json(itemDepartment);
        }

        #endregion Department

        #region Supplier

        [HttpPost("SupplierList")]
        public async Task<IActionResult> SupplierList()
        {
            var supplierList = await _inventoryDbContext.Suppliers.ToListAsync();
            return Json(supplierList);
        }

        #endregion Supplier

        #region Item

        [HttpPost("ItemList")]
        public async Task<IActionResult> ItemList()
        {
            var itemList = await _inventoryDbContext.Items.ToListAsync();
            // Retrieve the request's host and scheme
            var request = HttpContext.Request;
            string domain = $"{request.Scheme}://{request.Host.Value}";
            var itemListWithQR = itemList.Select(item => new
            {
                item.ItemID,
                item.UniqueID,
                item.CompanyId,
                item.DepartmentId,
                item.ProductId,
                item.SerialNumber,
                item.Quantity,
                item.Supplier,
                item.PurchaseDate,
                item.PONo,
                item.Currency,
                item.PriceInRM,
                item.CurrencyRate,
                item.ConvertPrice,
                item.DODate,
                item.Warranty,
                item.EndWDate,
                item.InvoiceDate,
                QRString = $"{domain}/Inventory/ItemInformation/{item.UniqueID}"
            }).ToList();
            return Json(itemListWithQR);
        }

        [HttpPost("GenerateItemQr/{id}")]
        public IActionResult GenerateItemQr(string id)
        {
            // Retrieve the request's host and scheme
            var request = HttpContext.Request;
            string domain = $"{request.Scheme}://{request.Host.Value}";

            // Append the QR path and item ID
            string QRString = $"{domain}/Inventory/ItemInformation/{id}";
            return Json(QRString);
        }

        [HttpPost("AddItem")]
        public async Task<IActionResult> AddItem([FromBody] ItemModel item)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            if (item == null)
            {
                return NotFound("Item is null");
            }

            try
            {
                var product = await _inventoryDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");

                var addToProduct = item.Quantity;
                product.QuantityProduct += addToProduct;

                if (product.Category == "Disposable")
                {
                    item.SerialNumber = null;
                }

                _inventoryDbContext.Items.Add(item);
                _inventoryDbContext.Products.Update(product);
                await _identityDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID

                // Fetch the generated ItemID
                var savedItem = await _inventoryDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);

                if (savedItem != null)
                {
                    var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
                    var itemProduct = _inventoryDbContext.Products.Where(p => p.ProductId == item.ProductId).FirstOrDefault();

                    string? companyInitial = companyDepartment!.CompanyName?.ToString().Substring(0, 1).ToUpper();
                    string? departmentInitial = companyDepartment!.DepartmentName?.ToString().Substring(0, 1).ToUpper();
                    char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
                    string? productId = itemProduct!.ProductId.ToString("D3");
                    string? itemId = item.ItemID.ToString("D5");
                    var uniqueId = $"{companyInitial}{departmentInitial}{initialCategory}{productId}{itemId}".ToUpper();
                    savedItem.UniqueID = uniqueId;

                    _inventoryDbContext.Items.Update(savedItem);
                    await _identityDbContext.SaveChangesAsync();
                }
                var updatedItem = new 
                {
                    savedItem!.ItemID,
                    savedItem.UniqueID,
                    savedItem.CompanyId,
                    savedItem.DepartmentId,
                    savedItem.ProductId,
                    savedItem.SerialNumber,
                    savedItem.Quantity,
                    savedItem.Supplier,
                    savedItem.PurchaseDate,
                    savedItem.PONo,
                    savedItem.Currency,
                    savedItem.PriceInRM,
                    savedItem.CurrencyRate,
                    savedItem.ConvertPrice,
                    savedItem.DODate,
                    savedItem.Warranty,
                    savedItem.EndWDate,
                    savedItem.InvoiceDate,
                };
                return Json(updatedItem);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("DeleteItem/{id}")]
        public async Task<IActionResult> DeleteItem(int id)
        {
            var item = await _inventoryDbContext.Items.FindAsync(id);
            if (item == null)
            {
                return NotFound(new { success = false, message = "Item not found" });
            }

            _inventoryDbContext.Items.Remove(item);
            await _identityDbContext.SaveChangesAsync();

            return Ok(new { success = true, message = "Item deleted successfully" });
        }

        #endregion Item
    }
}
