using Azure.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
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.Data;
using System.Diagnostics;
using System.Reflection;
using static System.Collections.Specialized.BitVector32;

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

    public class InvMainAPI : Controller
    {
        private readonly ILogger<InvMainAPI> _logger;
        private readonly CentralSystemContext _centralDbContext;
        private readonly UserManager<UserModel> _userManager;

        public InvMainAPI(ILogger<InvMainAPI> logger, CentralSystemContext centralDbContext, UserManager<UserModel> userManager)
        {
            _logger = logger;
            _centralDbContext = centralDbContext;
            _userManager = userManager;
        }

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

        public async Task<List<DepartmentCompany>> GetDepartmentWithCompanyList()
        {
            var departmentList = await _centralDbContext.Departments.ToListAsync();
            var companyList = await _centralDbContext.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 _centralDbContext.Departments.FirstOrDefaultAsync(d => d.DepartmentId == departmentId );
            var companyList = await _centralDbContext.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,
                DepartmentCode = departmentList.DepartmentCode,
            };

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

        #region Manufacturer

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

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

            try
            {
                _centralDbContext.Manufacturers.Add(new ManufacturerModel
                {
                    ManufacturerName = manufacturer.ManufacturerName,
                });
                await _centralDbContext.SaveChangesAsync();
                var updatedList = await _centralDbContext.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 _centralDbContext.Manufacturers.FindAsync(id);
            if (manufacturer == null)
            {
                return NotFound(new { success = false, message = "Manufacturer not found" });
            }

            _centralDbContext.Manufacturers.Remove(manufacturer);
            await _centralDbContext.SaveChangesAsync();

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

        #endregion Manufacturer

        #region Product

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

        [HttpPost("ProductListWithItem")]
        public async Task<IActionResult> ProductListWithItem()
        {
            var productList = await _centralDbContext.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";
                }
                _centralDbContext.Products.Add(product);
                await _centralDbContext.SaveChangesAsync();
                var updatedList = await _centralDbContext.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 _centralDbContext.Products.FindAsync(id);
            if (Product == null)
            {
                return NotFound(new { success = false, message = "Product not found" });
            }

            _centralDbContext.Products.Remove(Product);
            await _centralDbContext.SaveChangesAsync();

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

        #endregion Product

        #region Supplier

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

        [HttpPost("AddSupplier")]
        public async Task<IActionResult> AddSupplier([FromBody] SupplierModel supplier)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                _centralDbContext.Suppliers.Add(supplier);
                await _centralDbContext.SaveChangesAsync();
                var updatedList = await _centralDbContext.Suppliers.ToListAsync();
                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("DeleteSupplier/{id}")]
        public async Task<IActionResult> DeleteSupplier(int id)
        {
            var supplier = await _centralDbContext.Suppliers.FindAsync(id);
            if (supplier == null)
            {
                return NotFound(new { success = false, message = "Supplier not found" });
            }

            _centralDbContext.Suppliers.Remove(supplier);
            await _centralDbContext.SaveChangesAsync();

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

        #region Item

        [HttpPost("ItemList")]
        public async Task<IActionResult> ItemList()
        {
            try
            {
                var user = await _userManager.GetUserAsync(User);
                if (user == null)
                {
                    return BadRequest("User not found");
                }
                else
                {
                    user.departmentId = user.departmentId != null ? user.departmentId : 0;
                }

                var userRole = await _userManager.GetRolesAsync(user);
                var isAdmin = userRole.Contains("SystemAdmin") || userRole.Contains("SuperAdmin") || userRole.Contains("Finance");
                List<ItemModel> itemList = new List<ItemModel>();
                // Get the item list
                if (isAdmin)
                {
                    itemList = await _centralDbContext.Items
                        .AsNoTracking()
                        .Include("CreatedBy")
                        .Include("Department")
                        .Include("Product")
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStore)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStation)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromUser)
                        .ToListAsync();
                }
                else
                {
                    itemList = await _centralDbContext.Items
                        .AsNoTracking()
                        .Include("CreatedBy")
                        .Include("Department")
                        .Include("Product")
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStore)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStation)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromUser)
                        .Where(i => i.DepartmentId == user.departmentId)
                        .ToListAsync();
                }

                // Get the departments list (DepartmentId references Departments)
                var departments = await _centralDbContext.Departments.ToListAsync();

                // Now join items with users and departments manually
                var itemListWithDetails = itemList.Select(item => new
                {
                    item.ItemID,
                    item.UniqueID,
                    item.CompanyId,
                    item.DepartmentId,
                    item.ProductId,
                    item.SerialNumber,
                    item.Quantity,
                    item.Supplier,
                    PurchaseDate = item.PurchaseDate.ToString("dd/MM/yyyy"),
                    item.PONo,
                    item.Currency,
                    item.DefaultPrice,
                    item.CurrencyRate,
                    item.ConvertPrice,
                    item.DODate,
                    item.Warranty,
                    item.PartNumber,
                    EndWDate = item.EndWDate.ToString("dd/MM/yyyy"),
                    InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"),
                    item.Department?.DepartmentName,
                    CreatedBy=item.CreatedBy!.UserName,
                    item.Product!.ProductName,
                    item.Product!.ProductShortName,
                    item.Product!.Category,
                    //CurrentUser = item.Movement?.FromUser?.UserName,
                    FromUser = item.Movement?.ToUser,
                    FromStore = item.Movement?.ToStore,
                    FromStation = item.Movement?.ToStation,
                    CurrentUser = item.Movement?.FromUser?.UserName,
                    CurrentStore = item.Movement?.FromStore?.StoreName,
                    CurrentStation = item.Movement?.FromStation?.StationName,

                    QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String
                }).ToList();

                return Json(itemListWithDetails);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [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);
            }

            try
            {
                var product = await _centralDbContext.Products.FirstOrDefaultAsync(p => p.ProductId == item.ProductId) ?? throw new Exception("Product not found");
                var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == item.CreatedByUserId) ?? new InventoryMasterModel{ UserId = item.CreatedByUserId };
                var addToProduct = item.Quantity;
                product.QuantityProduct += addToProduct;

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

                _centralDbContext.Items.Add(item);
                _centralDbContext.Products.Update(product);

                await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID


                ItemMovementModel itemMovement = new ItemMovementModel
                {
                    ItemId = item.ItemID,
                    ToUser = inventoryMaster.UserId,
                    ToStore = inventoryMaster.StoreId,
                    LastStore = inventoryMaster.StoreId,
                    LastUser = inventoryMaster.UserId,
                    LatestStatus = "Ready To Deploy",
                    Quantity = item.Quantity,
                    Action= "Register",
                    Date = DateTime.Now,
                    MovementComplete = true,
                };

                _centralDbContext.ItemMovements.Add(itemMovement);
                await _centralDbContext.SaveChangesAsync();

                // Fetch the generated ItemID
                var savedItem = await _centralDbContext.Items.FirstOrDefaultAsync(i => i.ItemID == item.ItemID);
                // Fetch the generated itemMovement
                var savedMovement = await _centralDbContext.ItemMovements.FirstOrDefaultAsync(i => i.Id == itemMovement.Id);

                if (savedItem != null)
                {
                    var companyDepartment = await GetDepartmentWithCompany(item.CompanyId, item.DepartmentId);
                    var itemProduct = _centralDbContext.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();
                    string? deptCode = companyDepartment!.DepartmentCode?.ToString();
                    char? initialCategory = itemProduct!.Category.ToString().Substring(0, 1).ToUpper().FirstOrDefault();
                    string? productId = itemProduct!.ProductId.ToString("D3");
                    string? itemId = item.ItemID.ToString("D5");
                    var uniqueId = $"{deptCode}{initialCategory}{productId}{itemId}".ToUpper();
                    savedItem.UniqueID = uniqueId;
                    savedItem.MovementId = savedMovement?.Id;

                    _centralDbContext.Items.Update(savedItem);
                    await _centralDbContext.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.DefaultPrice,
                    savedItem.CurrencyRate,
                    savedItem.ConvertPrice,
                    savedItem.DODate,
                    savedItem.Warranty,
                    savedItem.EndWDate,
                    savedItem.InvoiceDate,
                    savedItem.PartNumber,
                };
                return Json(updatedItem);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

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

            _centralDbContext.Items.Remove(item);
            await _centralDbContext.SaveChangesAsync();

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

        [HttpPost("GetItem/{id}")] // Endpoint to retrieve an item by its ID
        public async Task<IActionResult> GetItem(string id)
        {
            var item = await _centralDbContext.Items
                        .Include("CreatedBy")
                        .Include("Department")
                        .Include("Product")
                        .Include("Movement")
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStore)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromStation)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.FromUser)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.NextStore)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.NextStation)
                        .Include(i => i.Movement)
                        .ThenInclude(m => m!.NextUser).FirstOrDefaultAsync(i => i.UniqueID == id);
            if (item == null){
                return NotFound(new { success = false, message = "Item not found" });
            }
            var singleItem = new
            {
                item.Movement?.Id,
                item.ItemID,
                item.MovementId,
                item.UniqueID,
                item.CompanyId,
                item.DepartmentId,
                item.ProductId,
                item.SerialNumber,
                item.Quantity,
                item.Supplier,
                PurchaseDate = item.PurchaseDate.ToString("dd/MM/yyyy"),
                item.PONo,
                item.Currency,
                item.DefaultPrice,
                item.CurrencyRate,
                item.ConvertPrice,
                item.DODate,
                item.Warranty,
                item.PartNumber,
                EndWDate = item.EndWDate.ToString("dd/MM/yyyy"),
                InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"),
                item.Department?.DepartmentName,
                item.CreatedBy!.UserName,
                item.Product!.ProductName,
                item.Product!.ProductShortName,
                item.Product!.ImageProduct,
                CurrentUser = item.Movement?.FromUser?.UserName,
                CurrentUserFullName = item.Movement?.FromUser?.FullName,
                CurrentUserId = item.Movement?.FromUser?.Id,
                CurrentStore = item.Movement?.FromStore?.StoreName,
                CurrentStoreId = item.Movement?.FromStore?.Id,
                CurrentStation = item.Movement?.FromStation?.StationName,
                CurrentStationId = item.Movement?.FromStation?.StationId,
                ToUser = item.Movement?.ToUser,
                ToUserName = item.Movement?.NextUser?.UserName,
                ToStore = item.Movement?.ToStore,
                ToStoreName = item.Movement?.NextStore?.StoreName,
                ToStation = item.Movement?.ToStation,
                ToStationName = item.Movement?.NextStation?.StationName,
                item.Movement?.ToOther, 
                item.Movement?.LatestStatus,
                item.Movement?.LastUser,
                item.Movement?.MovementComplete,
                remark = item.Movement?.Remark,
                QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String
            };
            return Json(singleItem);
        }

        #endregion Item

        #region ItemMovement

        [HttpPost("ItemMovementList")]
        public async Task<IActionResult> ItemMovementList()
        {

            //var itemMovementList = await _centralDbContext.ItemMovements.Include(i => i.NextUser).Include(i => i.Item).ThenInclude(i => i.Product).ToListAsync();

            var itemMovementList = await _centralDbContext.ItemMovements
                                        .Include(i => i.Item)
                                        .ThenInclude(i => i.Product)
                                        .Include(i => i.FromStore)
                                        .Include(i => i.FromStation)
                                        .Include(i => i.FromUser)
                                        .Include(i => i.NextStore)
                                        .Include(i => i.NextStation)
                                        .Include(i => i.NextUser)
                                        .Include(i => i.NextUser)
                                        .ToListAsync();
            //var itemList = await _centralDbContext.Items.ToListAsync();

            int itemrow = 0;
            var itemMovementListWithQR = itemMovementList.Select(item => new
            {
                id = itemrow++,
                item, // Includes all properties of the original item
                QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String
                ProductName = item.Item?.Product?.ProductName,
                toUserName = item.NextUser?.FullName,
                lastUserName = item.FromUser?.FullName
            }).ToList();
            //Console.WriteLine(Json(itemMovementList));


            //return Json(itemMovementList);
            //return Json(itemMovementListWithQR);

            return Json(itemMovementList.Select(i => new
            {
                i.Id,
                i.ItemId,
                i.ToStation,
                i.ToStore,
                i.ToUser,
                UniqueID = i.Item?.UniqueID,
                ProductName = i.Item?.Product?.ProductName,
                ProductCategory = i.Item?.Product?.Category,
                LastUserName = i.FromUser?.FullName,
                LastStoreName = i.FromStore?.StoreName,
                LastStationName = i.FromStation?.StationName,
                ToUserName = i.NextUser?.FullName,
                ToStoreName = i.NextStore?.StoreName,
                ToStationName = i.NextStation?.StationName,
                i.ToOther,
                i.sendDate,
                i.Action,
                i.Quantity,
                i.Remark,
                i.ConsignmentNote,
                i.Date,
                i.LastUser,
                i.LastStore,
                i.LastStation,
                i.LatestStatus,
                i.receiveDate,
                i.MovementComplete
            }));

            //return Json(itemMovementList.Select(item => new
            //{
            //    id = itemrow++,
            //    item,
            //     QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.ItemId}", // Generate QR String
            //    ProductName = item.Item?.Product?.ProductName,
            //    toUserName = item.NextUser?.FullName,
            //    lastUserName = item.FromUser?.FullName
            //}));
        }

        [HttpPost("AddItemMovement")]
        public async Task<IActionResult> AddItemMovement([FromBody] ItemMovementModel itemmovement)
        {

            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                //if (itemmovement.ToUser == null)
                //{
                //    throw new Exception("itemmovement.ToUser is null");
                //}

                //var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == itemmovement.ToUser) ?? new InventoryMasterModel { UserId = itemmovement.ToUser };
                var inventoryMaster = await _centralDbContext.InventoryMasters.Include("User").FirstOrDefaultAsync(i => i.UserId == itemmovement.ToUser);
                if (inventoryMaster != null)
                {
                    itemmovement.ToStore = inventoryMaster.StoreId;
                }


                if (!string.IsNullOrEmpty(itemmovement.ConsignmentNote))
                {
                    var bytes = Convert.FromBase64String(itemmovement.ConsignmentNote);
                    string filePath = "";

                    string uniqueName = $"{itemmovement.ItemId}_{Guid.NewGuid()}";

                    if (IsImage(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", uniqueName + itemmovement.ItemId + "_Request.jpg");
                        itemmovement.ConsignmentNote = "/media/inventory/itemmovement/" + uniqueName + itemmovement.ItemId + "_Request.jpg";
                    }
                    else if (IsPdf(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", uniqueName + itemmovement.ItemId + "_Request.pdf");
                        itemmovement.ConsignmentNote = "/media/inventory/itemmovement/" + uniqueName + itemmovement.ItemId + "_Request.pdf";
                    }
                    else
                    {
                        return BadRequest("Unsupported file format.");
                    }

                    await System.IO.File.WriteAllBytesAsync(filePath, bytes);
                }

                _centralDbContext.ItemMovements.Add(itemmovement);

                await _centralDbContext.SaveChangesAsync(); // This generates the auto-incremented ItemID

                var updateItem = await _centralDbContext.Items.FindAsync(itemmovement.ItemId); //only access after it have its own itemmovent 

                if (updateItem != null)
                {
                    if (itemmovement.ToOther == "On Delivery")
                    {
                        updateItem.ItemStatus = 2;
                    }
                    else if (itemmovement.ToOther == "Repair" || itemmovement.ToOther == "Calibration")
                    {
                        updateItem.ItemStatus = 4;
                    }
                    else if (itemmovement.ToOther == "Faulty")
                    {
                        updateItem.ItemStatus = 8;
                    }

                    //Console.WriteLine("updateItem.MovementId" + updateItem.MovementId);
                    //Console.WriteLine("itemmovement.Id" + itemmovement.Id);

                    updateItem.MovementId = itemmovement.Id;
                    _centralDbContext.Items.Update(updateItem);
                    await _centralDbContext.SaveChangesAsync(); // save changes for table item - movementid


                }
                return Json(new
                {
                    itemmovement.Id,
                    itemmovement.ItemId,
                    itemmovement.ToStation,
                    itemmovement.ToStore,
                    itemmovement.ToUser,
                    itemmovement.ToOther,
                    itemmovement.sendDate,
                    itemmovement.Action,
                    itemmovement.Quantity,
                    itemmovement.Remark,
                    itemmovement.ConsignmentNote,
                    itemmovement.Date,
                    itemmovement.LastUser,
                    itemmovement.LastStore,
                    itemmovement.LastStation,
                    itemmovement.LatestStatus,
                    itemmovement.receiveDate,
                    itemmovement.MovementComplete
                });




                //return Json(itemmovement);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }

        }

        [HttpPost("UpdateItemMovementMaster")]
        public async Task<IActionResult> UpdateItemMovementMaster([FromBody] ItemMovementModel receiveMovement)
        {

            try
            {

                var updatedList = await _centralDbContext.ItemMovements.FindAsync(receiveMovement.Id);

                if (updatedList == null)
                {
                    return NotFound("Item movement record not found.");
                }

                updatedList.LatestStatus = receiveMovement.LatestStatus;
                updatedList.receiveDate = receiveMovement.receiveDate;
                updatedList.Remark = receiveMovement.Remark;
                updatedList.MovementComplete = true;

                _centralDbContext.ItemMovements.Update(updatedList);
                await _centralDbContext.SaveChangesAsync();

                //var receiveItems = await _centralDbContext.Items.FindAsync(receiveMovement.ItemId);

                //if (receiveItems != null)
                //{
                //    receiveItems.ItemStatus = 3;
                //    _centralDbContext.Items.Update(receiveItems);

                //    await _centralDbContext.SaveChangesAsync(); // Simpan perubahan
                //}

                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        #endregion ItemMovement

        #region ItemMovementUser

        [HttpPost("ItemMovementUser")]
        public async Task<IActionResult> ItemMovementUser()
        {
            try
            {
                var user = await _userManager.GetUserAsync(User);
                if (user == null)
                {
                    return NotFound("Item movement record not found.");
                }

                var itemMovementUser = await _centralDbContext.ItemMovements
                                        .Include(i => i.Item)
                                        .ThenInclude(i => i.Product)
                                        .Include(i => i.FromStore)
                                        .Include(i => i.FromStation)
                                        .Include(i => i.FromUser)
                                        .Include(i => i.NextStore)
                                        .Include(i => i.NextStation)
                                        .Include(i => i.NextUser)
                                        .Where(i => i.ToUser == user.Id || i.LastUser == user.Id)
                                        .ToListAsync();

                return Json(itemMovementUser.Select(i => new
                    {
                        i.Id,
                        i.ItemId,
                        i.ToStation,
                        i.ToStore,
                        i.ToUser,
                        UniqueID = i.Item?.UniqueID,
                        ProductName = i.Item?.Product?.ProductName,
                        LastUserName = i.FromUser?.FullName,
                        LastStoreName = i.FromStore?.StoreName,
                        LastStationName = i.FromStation?.StationName,
                        ToUserName = i.NextUser?.FullName,
                        ToStoreName = i.NextStore?.StoreName,
                        ToStationName = i.NextStation?.StationName,
                        i.ToOther,
                        i.sendDate,
                        i.Action,
                        i.Quantity,
                        i.Remark,
                        i.ConsignmentNote,
                        i.Date,
                        i.LastUser,
                        i.LastStore,
                        i.LastStation,
                        i.LatestStatus,
                        i.receiveDate,
                        i.MovementComplete
                    }));
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }

        }
        #endregion

        #region ItemRequestUser
        [HttpPost("AddRequest")]
        public async Task<IActionResult> AddRequest([FromBody] RequestModel request)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                if (!string.IsNullOrEmpty(request.Document))
                {
                    var findUniqueCode = _centralDbContext.Products.FirstOrDefault(r => r.ProductId == request.ProductId);
                    var findUniqueUser = _centralDbContext.Users.FirstOrDefault(r => r.Id == request.UserId);

                    var bytes = Convert.FromBase64String(request.Document);
                    string filePath = "";

                    var uniqueAbjad = new string(Enumerable.Range(0, 8).Select(_ => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[new Random().Next(36)]).ToArray());


                    if (IsImage(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.jpg");
                        request.Document = "/media/inventory/request/" + findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.jpg";
                    }
                    else if (IsPdf(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/request", findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "_Request.pdf");
                        request.Document = "/media/inventory/request/" + findUniqueUser.FullName + " " + findUniqueCode.ModelNo + "(" + uniqueAbjad + ") Request.pdf";
                    }
                    else
                    {
                        return BadRequest("Unsupported file format.");
                    }

                    await System.IO.File.WriteAllBytesAsync(filePath, bytes);
                }

                _centralDbContext.Requests.Add(request);
                await _centralDbContext.SaveChangesAsync();

                var updatedList = await _centralDbContext.Requests
                                        .Where(r => r.UserId == request.UserId)
                                        .ToListAsync();

                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
        private bool IsImage(byte[] bytes)
        {
            // JPEG file signature: FF D8 FF
            if (bytes.Length > 2 && bytes[0] == 0xFF && bytes[1] == 0xD8 && bytes[2] == 0xFF)
                return true;

            // PNG file signature: 89 50 4E 47 0D 0A 1A 0A
            if (bytes.Length > 7 && bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4E && bytes[3] == 0x47)
                return true;

            // GIF file signature: GIF87a or GIF89a
            if (bytes.Length > 5 && bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46)
                return true;

            return false;
        }

        private bool IsPdf(byte[] bytes)
        {
            // PDF file signature: 25 50 44 46 (ASCII for "%PDF")
            return bytes.Length > 3 && bytes[0] == 0x25 && bytes[1] == 0x50 && bytes[2] == 0x44 && bytes[3] == 0x46;
        }

        [HttpGet("ItemRequestListEachUser/{userId}")]
        public async Task<IActionResult> ItemRequestListEachUser(int userId)
        {
            var requests = await _centralDbContext.Requests
                .Include(i => i.Product).Include(i => i.Station).Where(r => r.UserId == userId).ToListAsync();

            return Json(requests.Select(i => new
            {
                i.requestId,
                i.ProductId,
                productName = i.Product?.ProductName,
                i.UserId,
                i.status,
                i.StationId,
                stationName = i.Station?.StationName,
                i.RequestQuantity,
                i.requestDate,
                i.ProductCategory,
                i.Document,
                i.approvalDate,
                i.remarkMasterInv,
                i.remarkUser,
            }));
        }

        [HttpDelete("DeleteRequest/{requestId}")]
        public async Task<IActionResult> DeleteRequest(int requestId)
        {
            var request = await _centralDbContext.Requests.FindAsync(requestId);
            if (request == null)
            {
                return NotFound(new { success = false, message = "Request not found" });
            }

            _centralDbContext.Requests.Remove(request);
            await _centralDbContext.SaveChangesAsync();

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

        #endregion

        #region ItemRequestAdmin
        [HttpGet("ItemRequestList")]
        public async Task<IActionResult> ItemRequestList()
        {

            var itemRequestList = await _centralDbContext.Requests.Include(i => i.Product).Include(i => i.User).ToListAsync();
            return Json(itemRequestList.Select(i => new
            {
                i.requestId,
                productName = i.Product?.ProductName,
                i.ProductId,
                userName = i.User?.FullName,
                i.status,
                i.StationId,
                i.RequestQuantity,
                i.requestDate,
                i.ProductCategory,
                i.Document,
                i.approvalDate,
                i.remarkMasterInv,
                i.remarkUser,
               
            }));

        }

        [HttpPost("ApproveRequest/{id}")]
        public async Task<IActionResult> ApproveRequest(int id, [FromBody] RequestModel request)
        {
            var Request = await _centralDbContext.Requests.FindAsync(id);
            if (Request == null)
            {
                return NotFound(new { success = false, message = "Request not found" });
            }

            Request.status = "Approved";
            Request.remarkMasterInv = request.remarkMasterInv;
            Request.approvalDate = DateTime.UtcNow;
            _centralDbContext.SaveChanges();

            return Ok(new { success = true, message = "Request Approved Successfully", data = Request });
        }

        [HttpPost("RejectRequest/{id}")]
        public async Task<IActionResult> RejectRequest(int id, [FromBody] RequestModel request)
        {


            var Request = await _centralDbContext.Requests.FindAsync(id);
            if (Request == null)
            {
                return NotFound(new { success = false, message = "Request not found" });
            }

            Request.status = "Rejected";
            Request.remarkMasterInv = request.remarkMasterInv;
            Request.approvalDate = DateTime.UtcNow;
            _centralDbContext.SaveChanges();

            return Ok(new { success = true, message="Request Rejected Successfully", data=Request });
        }

        #endregion ItemRequestAdmin

        #region ItemReport

        [HttpPost("GetInventoryReport/{deptId}")]
        public async Task<IActionResult> GetInventoryReport(int deptId)
        {
            try{
                var user = await _userManager.GetUserAsync(User);

                var userRole = await _userManager.GetRolesAsync(user ?? new UserModel());
                List<ItemModel> items = new List<ItemModel>();
                if (userRole.Contains("SuperAdmin") && userRole.Contains("SystemAdmin")) 
                {
                    items = await _centralDbContext.Items
                    .Include("CreatedBy")
                    .Include("Department")
                    .Include("Product")
                    .ToListAsync();
                }
                else
                {
                    items = await _centralDbContext.Items
                    .Include("CreatedBy")
                    .Include("Department")
                    .Include("Product")
                    .Where(i => i.DepartmentId == deptId)
                    .ToListAsync();
                }
                var itemListWithDetails = items.Where(i => i.Quantity > 0).Select(item => new
                {
                    item.ItemID,
                    item.UniqueID,
                    item.CompanyId,
                    item.DepartmentId,
                    item.ProductId,
                    item.SerialNumber,
                    item.Quantity,
                    item.Supplier,
                    PurchaseDate = item.PurchaseDate.ToString("dd/MM/yyyy"),
                    item.PONo,
                    item.Currency,
                    item.DefaultPrice,
                    item.CurrencyRate,
                    item.ConvertPrice,
                    item.DODate,
                    item.Warranty,
                    EndWDate = item.EndWDate.ToString("dd/MM/yyyy"),
                    InvoiceDate = item.InvoiceDate?.ToString("dd/MM/yyyy"),
                    item.Department?.DepartmentName,
                    CreatedBy = item.CreatedBy!.UserName,
                    item.Product!.ProductName,
                    item.Product!.ProductShortName,
                    item.Product!.Category,
                    //CurrentUser = item.Movement?.FromUser?.UserName,
                    CurrentUser = item.Movement?.FromUser?.UserName,
                    CurrentStore = item.Movement?.FromStore?.StoreName,
                    CurrentStation = item.Movement?.FromStation?.StationName,

                    QRString = $"{HttpContext.Request.Scheme}://{HttpContext.Request.Host.Value}/I/{item.UniqueID}" // Generate QR String
                }).ToList();

                int itemCountRegistered = items.Count;
                int itemCountStillInStock = items.Where(i => i.Quantity > 0).Count();
                var itemsMovementsThisMonth = _centralDbContext.ItemMovements
                .Where(i => i.Date.Month == DateTime.Now.Month);
                int itemCountRegisteredThisMonth = itemsMovementsThisMonth.Count(i => i.Action == "Register");
                int itemCountStockOutThisMonth = itemsMovementsThisMonth.Count(i => i.Action == "Stock Out");

                var lastMonth = DateTime.Now.AddMonths(-1).Month;
                var itemsMovementsLastMonth = _centralDbContext.ItemMovements
                .Where(i => i.Date.Month == lastMonth);
                int itemCountRegisteredLastMonth = itemsMovementsLastMonth.Count(i => i.Action == "Register");
                int itemCountStockOutLastMonth = itemsMovementsLastMonth.Count(i => i.Action == "Stock Out");

                var report = new
                {
                    itemListWithDetails,
                    itemCountRegistered,
                    itemCountStillInStock,
                    itemCountRegisteredThisMonth,
                    itemCountStockOutThisMonth,
                    itemCountRegisteredLastMonth,
                    itemCountStockOutLastMonth
                };
                return Json(report);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        #endregion

        #region Station
        [HttpPost("StationList")]
        public async Task<IActionResult> StationList()
        {
            var stationList = await _centralDbContext.Stations.Include(i => i.StationPic).ToListAsync();
            return Json(stationList);
        }

        [HttpPost("AddStation")]
        public async Task<IActionResult> AddStation([FromBody] StationModel station)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                _centralDbContext.Stations.Add(station);
                await _centralDbContext.SaveChangesAsync();
                var updatedList = await _centralDbContext.Stations.ToListAsync();
                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpDelete("DeleteStation/{id}")]
        public async Task<IActionResult> DeleteStation(int id)
        {
            var station = await _centralDbContext.Stations.FindAsync(id);
            if (station == null)
            {
                return NotFound(new { success = false, message = "Station not found" });
            }

            _centralDbContext.Stations.Remove(station);
            await _centralDbContext.SaveChangesAsync();

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

        #region Store

        [HttpPost("StoreList")]
        public async Task<IActionResult> StoreList()
        {
            var storeList = await _centralDbContext.Stores.ToListAsync();
            return Json(storeList);
        }

        [HttpPost("StoreSpecificMaster/{storeId}")]
        public async Task<IActionResult> StoreSpecificMaster(int storeId)
        {
            var storeList = await _centralDbContext.InventoryMasters.Where(i => i.StoreId == storeId).FirstOrDefaultAsync();
            return Json(storeList);
        }

        #endregion Store

        #region AllUser

        [HttpPost("UserList")]
        public async Task<IActionResult> UserList()
        {
            var userList = await _centralDbContext.Users.ToListAsync();
            return Json(userList);
        }


        #endregion AllUser

        #region ScannerUser
        [HttpPost("UpdateItemMovementUser")]
        public async Task<IActionResult> UpdateItemMovementUser([FromBody] ItemMovementModel receiveMovement)
        {

            try
            {

                var updatedList = await _centralDbContext.ItemMovements.FindAsync(receiveMovement.Id);

                if (updatedList == null)
                {
                    return NotFound("Item movement record not found.");
                }

                updatedList.LatestStatus = receiveMovement.LatestStatus;
                updatedList.receiveDate = receiveMovement.receiveDate;
                updatedList.MovementComplete = receiveMovement.MovementComplete;

                _centralDbContext.ItemMovements.Update(updatedList);
                await _centralDbContext.SaveChangesAsync();

                var receiveItems = await _centralDbContext.Items.FindAsync(receiveMovement.ItemId);

                if (receiveItems != null)
                {
                    receiveItems.ItemStatus = 3;
                    _centralDbContext.Items.Update(receiveItems);

                }

                await _centralDbContext.SaveChangesAsync();

                return Json(updatedList);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPost("ReturnItemMovementUser")]
        public async Task<IActionResult> ReturnItemMovementUser([FromBody] ItemMovementModel returnMovement)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                if (!string.IsNullOrEmpty(returnMovement.ConsignmentNote))
                {
                    var findUniqueCode = _centralDbContext.Items.Include(i => i.Product).FirstOrDefault(r => r.ItemID == returnMovement.ItemId);
                    var findUniqueUser = _centralDbContext.Users.FirstOrDefault(r => r.Id == returnMovement.ToUser);

                    var bytes = Convert.FromBase64String(returnMovement.ConsignmentNote);
                    string filePath = "";

                    var uniqueAbjad = new string(Enumerable.Range(0, 8).Select(_ => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[new Random().Next(36)]).ToArray());


                    if (IsImage(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Return.jpg");
                        returnMovement.ConsignmentNote = "/media/inventory/itemmovement/" + findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Return.jpg";
                    }
                    else if (IsPdf(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "Return.pdf");
                        returnMovement.ConsignmentNote = "/media/inventory/itemmovement/" + findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Return.pdf";
                    }
                    else
                    {
                        return BadRequest("Unsupported file format.");
                    }

                    await System.IO.File.WriteAllBytesAsync(filePath, bytes);
                }

                _centralDbContext.ItemMovements.Add(returnMovement);
                await _centralDbContext.SaveChangesAsync();

                var updateItemIdMovement = await _centralDbContext.ItemMovements
                    .FirstOrDefaultAsync(m => m.Id == returnMovement.Id && m.MovementComplete == false);

                if (updateItemIdMovement != null)
                {
                    var returnItems = await _centralDbContext.Items.FindAsync(updateItemIdMovement.ItemId);

                    if (returnItems != null)
                    {
                        returnItems.MovementId = updateItemIdMovement.Id;
                        returnItems.ItemStatus = 2;
                        _centralDbContext.Items.Update(returnItems);
                        await _centralDbContext.SaveChangesAsync(); // Simpan perubahan
                    }
                }

                return Json(new
                {
                    updateItemIdMovement.Id,
                    updateItemIdMovement.ItemId,
                    updateItemIdMovement.ToStation,
                    updateItemIdMovement.ToStore,
                    updateItemIdMovement.ToUser,
                    updateItemIdMovement.ToOther,
                    updateItemIdMovement.sendDate,
                    updateItemIdMovement.Action,
                    updateItemIdMovement.Quantity,
                    updateItemIdMovement.Remark,
                    updateItemIdMovement.ConsignmentNote,
                    updateItemIdMovement.Date,
                    updateItemIdMovement.LastUser,
                    updateItemIdMovement.LastStore,
                    updateItemIdMovement.LastStation,
                    updateItemIdMovement.LatestStatus,
                    updateItemIdMovement.receiveDate,
                    updateItemIdMovement.MovementComplete
                });

            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }

        [HttpPost("StationItemMovementUser")]
        public async Task<IActionResult> StationItemMovementUser([FromBody] ItemMovementModel stationMovement)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                if (!string.IsNullOrEmpty(stationMovement.ConsignmentNote))
                {
                    var findUniqueCode = _centralDbContext.Items.Include(i => i.Product).FirstOrDefault(r => r.ItemID == stationMovement.ItemId);
                    var findUniqueUser = _centralDbContext.Users.FirstOrDefault(r => r.Id == stationMovement.ToUser);

                    var bytes = Convert.FromBase64String(stationMovement.ConsignmentNote);
                    string filePath = "";

                    var uniqueAbjad = new string(Enumerable.Range(0, 8).Select(_ => "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[new Random().Next(36)]).ToArray());


                    if (IsImage(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Station.jpg");
                        stationMovement.ConsignmentNote = "/media/inventory/itemmovement/" + findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Station.jpg";
                    }
                    else if (IsPdf(bytes))
                    {
                        filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/media/inventory/itemmovement", findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "Return.pdf");
                        stationMovement.ConsignmentNote = "/media/inventory/itemmovement/" + findUniqueUser.FullName + " " + findUniqueCode.Product?.ModelNo + "(" + uniqueAbjad + ") Station.pdf";
                    }
                    else
                    {
                        return BadRequest("Unsupported file format.");
                    }

                    await System.IO.File.WriteAllBytesAsync(filePath, bytes);
                }

                _centralDbContext.ItemMovements.Add(stationMovement);
                await _centralDbContext.SaveChangesAsync();

                var updateItemIdMovement = await _centralDbContext.ItemMovements.Include(i => i.Item)
                    .FirstOrDefaultAsync(m => m.Id == stationMovement.Id);


                if (updateItemIdMovement != null)
                {
                    var returnItems = await _centralDbContext.Items.FindAsync(updateItemIdMovement.ItemId);

                    if (returnItems != null)
                    {
                        returnItems.MovementId = updateItemIdMovement.Id;
                        returnItems.ItemStatus = 3;

                        _centralDbContext.Items.Update(returnItems); // Simpan perubahan
                        await _centralDbContext.SaveChangesAsync();
                    }
                }

                return Json(new
                {
                    updateItemIdMovement.Id,
                    updateItemIdMovement.ItemId,
                    updateItemIdMovement.Item?.UniqueID,
                    updateItemIdMovement.ToStation,
                    updateItemIdMovement.ToStore,
                    updateItemIdMovement.ToUser,
                    updateItemIdMovement.ToOther,
                    updateItemIdMovement.sendDate,
                    updateItemIdMovement.Action,
                    updateItemIdMovement.Quantity,
                    updateItemIdMovement.Remark,
                    updateItemIdMovement.ConsignmentNote,
                    updateItemIdMovement.Date,
                    updateItemIdMovement.LastUser,
                    updateItemIdMovement.LastStore,
                    updateItemIdMovement.LastStation,
                    updateItemIdMovement.LatestStatus,
                    updateItemIdMovement.receiveDate,
                    updateItemIdMovement.MovementComplete
                });


            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
        
        #endregion
    }
}
