//controller
using av_motion_api.Data;
using av_motion_api.Models;
using av_motion_api.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Security.Claims;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace av_motion_api.Controllers
{
    [Route("api/supplier/[controller]")]
    [ApiController]
    public class SupplierController : ControllerBase
    {
        private readonly AppDbContext _appContext;
        private readonly ILogger<SupplierController> _logger;

        public SupplierController(AppDbContext context, ILogger<SupplierController> logger)
        {
            _appContext = context;
            _logger = logger;
        }

        // GET: api/supplier/GetSuppliers
        [HttpGet]
        [Route("GetSuppliers")]
        //[Authorize(Roles = "Administrator")]
        public async Task<ActionResult<IEnumerable<Supplier>>> GetSuppliers()
        {
            var suppliers = await _appContext.Suppliers.ToListAsync();
            return suppliers;
        }

        // GET: api/supplier/GetSupplier/{id}
        [HttpGet]
        [Route("GetSupplier/{id}")]
        //[Authorize(Roles = "Administrator")]
        public async Task<ActionResult<Supplier>> GetSupplier(int id)
        {
            if (_appContext.Suppliers == null)
            {
                return NotFound();
            }
            var supplier = await _appContext.Suppliers.FindAsync(id);
            if (supplier == null)
            {
                return NotFound();
            }
            return supplier;
        }

        // POST: api/supplier/PostSupplier
        [HttpPost]
        [Route("PostSupplier")]
        //[Authorize(Roles = "Administrator")]
        public async Task<ActionResult<Supplier>> PostSupplier([FromBody] Supplier supplier)
        {
            if (_appContext.Suppliers == null)
            {
                return Problem("Entity set 'AppDbContext.Suppliers' is null.");
            }

            var supplierEntity = new Supplier
            {
                Name = supplier.Name,
                Contact_Number = supplier.Contact_Number,
                Email_Address = supplier.Email_Address,
                Physical_Address = supplier.Physical_Address,
            };

            _appContext.Suppliers.Add(supplierEntity);
            await _appContext.SaveChangesAsync();
            return Ok(supplier);
        }

        // PUT: api/supplier/PutSupplier/{id}
        [HttpPut]
        [Route("PutSupplier/{id}")]
        //[Authorize(Roles = "Administrator")]
        public async Task<IActionResult> PutSupplier(int id, [FromBody] SupplierViewModel supplier)
        {
            var supplierEntity = await _appContext.Suppliers.FindAsync(id);

            if (supplierEntity == null)
            {
                return NotFound();
            }

            supplierEntity.Name = supplier.Name;
            supplierEntity.Contact_Number = supplier.Contact_Number;
            supplierEntity.Email_Address = supplier.Email_Address;
            supplierEntity.Physical_Address = supplier.Physical_Address;

            try
            {
                _appContext.Suppliers.Update(supplierEntity);
                await _appContext.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!SupplierExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return NoContent();
        }

        // DELETE: api/supplier/DeleteSupplier/{id}
        [HttpDelete]
        [Route("DeleteSupplier/{id}")]
        //[Authorize(Roles = "Administrator")]
        public async Task<IActionResult> DeleteSupplier(int id)
        {
            if (_appContext.Suppliers == null)
            {
                return NotFound();
            }
            var supplier = await _appContext.Suppliers.FindAsync(id);
            if (supplier == null)
            {
                return NotFound();
            }

            _appContext.Suppliers.Remove(supplier);
            await _appContext.SaveChangesAsync();
            return NoContent();
        }

        private bool SupplierExists(int id)
        {
            return (_appContext.Suppliers?.Any(e => e.Supplier_ID == id)).GetValueOrDefault();
        }

        // GET: api/supplier/GetAllSupplierOrders
        [HttpGet]
        [Route("GetAllSupplierOrders")]
        //[Authorize(Roles = "Administrator")]
        public async Task<IActionResult> GetAllSupplierOrders()
        {
            var orders = await _appContext.Supplier_Orders
                    .Include(o => o.Supplier)
                    .Include(o => o.Owner)
                    .Include(o => o.Supplier_Order_Lines)
                    .ThenInclude(sol => sol.Product)
                    .ToListAsync();

            var supplierOrderViewModels = orders.Select(order => new SupplierOrderViewModel
            {
                Supplier_Order_ID = order.Supplier_Order_ID,
                Date = order.Date,
                Supplier_ID = order.Supplier_ID,
                Supplier_Name = order.Supplier.Name,
                Owner_ID = order.Owner_ID,
                Status = order.Status,
                Supplier_Order_Details = order.Supplier_Order_Details,
                OrderLines = order.Supplier_Order_Lines.Select(sol => new SupplierOrderLineViewModel
                {
                    Supplier_Order_Line_ID = sol.Supplier_Order_Line_ID,
                    Product_ID = sol.Product_ID,
                    Product_Name = sol.Product.Product_Name,
                    Supplier_Quantity = sol.Supplier_Quantity,
                    Purchase_Price = sol.Purchase_Price
                }).ToList(),
                Total_Price = (decimal)order.Supplier_Order_Lines.Sum(sol => sol.Supplier_Quantity * sol.Purchase_Price)
            }).ToList();

            return Ok(supplierOrderViewModels);
        }

        // GET: api/supplier/GetSupplierOrderById/{id}
        [HttpGet]
        [Route("GetSupplierOrderById/{id}")]
        //[Authorize(Roles = "Administrator")]
        public async Task<IActionResult> GetSupplierOrderById(int id)
        {
            try
            {
                var order = await _appContext.Supplier_Orders
                    .Include(o => o.Supplier)
                    .Include(o => o.Owner)
                    .Include(o => o.Supplier_Order_Lines)
                    .ThenInclude(sol => sol.Product)
                    .FirstOrDefaultAsync(o => o.Supplier_Order_ID == id);

                if (order == null)
                {
                    return NotFound("Supplier order not found.");
                }

                return Ok(order);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching supplier order by ID.");
                return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while processing your request.");
            }
        }

        // GET: api/supplier/GetSupplierOrderDetails/{orderId}
        [HttpGet]
        [Route("GetSupplierOrderDetails/{orderId}")]
        public async Task<IActionResult> GetSupplierOrderDetails(int orderId)
        {
            try
            {
                var orderDetails = await (from sol in _appContext.Supplier_Order_Lines
                                          join p in _appContext.Products on sol.Product_ID equals p.Product_ID
                                          where sol.Supplier_Order_ID == orderId
                                          select new SupplierOrderDetailsViewModel
                                          {
                                              Supplier_Order_Line_ID = sol.Supplier_Order_Line_ID,
                                              Supplier_Order_ID = sol.Supplier_Order_ID,
                                              Product_ID = sol.Product_ID,
                                              Supplier_Quantity = sol.Supplier_Quantity,
                                              Purchase_Price = p.Purchase_Price ?? 0, // Handle nullable Purchase_Price
                                              Total_Price = (sol.Supplier_Quantity * (p.Purchase_Price ?? 0)), // Calculate Total_Price
                                              Product_Name = p.Product_Name
                                          }).ToListAsync();

                if (orderDetails == null || orderDetails.Count == 0)
                {
                    return NotFound("No order details found for the given order ID.");
                }

                return Ok(orderDetails);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error retrieving supplier order details.");
                return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while processing your request.");
            }
        }

        [HttpGet]
        [Route("GetProductCategories")]
        public async Task<IActionResult> GetProductCategories()
        {
            var categories = await _appContext.Product_Categories.ToListAsync();
            return Ok(categories);
        }

        // Controller to fetch products by category ID
        [HttpGet]
        [Route("GetProductsByCategory/{categoryId}")]
        public async Task<IActionResult> GetProductsByCategory(int categoryId)
        {
            var products = await _appContext.Products.Where(p => p.Product_Category_ID == categoryId).ToListAsync();
            return Ok(products);
        }
        
        [HttpPost]
        [Route("PlaceSupplierOrder")]
        public async Task<IActionResult> PlaceSupplierOrder([FromBody] SupplierOrderViewModel orderVm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Create a new supplier order
            var supplierOrder = new Supplier_Order
            {
                Date = DateTime.UtcNow,
                Supplier_Order_Details = orderVm.Supplier_Order_Details,
                Supplier_ID = orderVm.Supplier_ID,
                Owner_ID = orderVm.Owner_ID,
                Status = orderVm.Status,
                Supplier_Order_Lines = new List<Supplier_Order_Line>()
            };

            decimal totalOrderPrice = 0;

            Console.WriteLine($"Creating Supplier_Order with ID {supplierOrder.Supplier_Order_ID}");
            Console.WriteLine($"OrderLines count: {orderVm.OrderLines?.Count ?? 0}");

            // Process each order line
            foreach (var orderLine in orderVm.OrderLines)
            {

                // Fetch the product details
                var product = await _appContext.Products.FindAsync(orderLine.Product_ID);
                if (product == null)
                {
                    return BadRequest($"Product with ID {orderLine.Product_ID} not found.");
                }

                if (product != null)
                {
                    var purchasePrice = product.Purchase_Price;
                    if (purchasePrice == null)
                    {
                        return BadRequest($"Purchase price for product ID {orderLine.Product_ID} is not set.");
                    }

                    // Create a new supplier order line
                    var supplierOrderLine = new Supplier_Order_Line
                    {
                        Product_ID = orderLine.Product_ID,
                        Supplier_Quantity = orderLine.Supplier_Quantity,
                        Purchase_Price = purchasePrice // Set the purchase price from product
                    };

                    // Add the order line to the supplier order
                    supplierOrder.Supplier_Order_Lines.Add(supplierOrderLine);

                    // Calculate total price
                    totalOrderPrice += orderLine.Supplier_Quantity * (decimal)purchasePrice;
                }

                Console.WriteLine($"Processing OrderLine: Product_ID = {orderLine.Product_ID}, Quantity = {orderLine.Supplier_Quantity}");
            }

            // Set total price on supplier order
            supplierOrder.Total_Price = totalOrderPrice;

            // Save the supplier order to the database
            _appContext.Supplier_Orders.Add(supplierOrder);
            await _appContext.SaveChangesAsync();

            return Ok(supplierOrder);
        }

        // PUT: api/supplier/updateinventory
        [HttpPut]
        [Route("updateinventory")]
        //[Authorize(Roles = "Administrator")]
        public async Task<IActionResult> UpdateInventory([FromBody] UpdateInventoryViewModel updateInventoryVm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            try
            {
                var receivedSupplierOrder = new Received_Supplier_Order
                {
                    Supplies_Received_Date = updateInventoryVm.Supplies_Received_Date
                };

                _appContext.Received_Supplier_Orders.Add(receivedSupplierOrder);
                await _appContext.SaveChangesAsync();

                foreach (var line in updateInventoryVm.ReceivedOrderLines)
                {
                    var receivedOrderLine = new Received_Supplier_Order_Line
                    {
                        Received_Supplier_Order_ID = receivedSupplierOrder.Received_Supplier_Order_ID,
                        Received_Supplies_Quantity = line.Received_Supplies_Quantity,
                        Supplier_Order_Line_ID = line.Supplier_Order_Line_ID,
                    };

                    var product = await _appContext.Products.FindAsync(line.Product_ID);
                    if (product != null)
                    {
                        product.Quantity += line.Received_Supplies_Quantity;
                        _appContext.Products.Update(product);
                    }

                    _appContext.Received_Supplier_Order_Lines.Add(receivedOrderLine);
                }

                await _appContext.SaveChangesAsync();

                return Ok("Inventory updated successfully.");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error updating inventory.");
                return StatusCode(StatusCodes.Status500InternalServerError, "An error occurred while processing your request.");
            }
        }

        // POST: api/supplier/receivesupplierorder
        [HttpPost]
        [Route("receivesupplierorder")]

        public async Task<IActionResult> ReceiveSupplierOrder([FromBody] ReceivedSupplierOrderViewModel receiveOrderVm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var receivedSupplierOrder = new Received_Supplier_Order
            {
                Supplies_Received_Date = receiveOrderVm.Supplies_Received_Date,
                Discrepancies = receiveOrderVm.Discrepancies,
                Accepted = receiveOrderVm.Accepted ?? false,
                Received_Supplier_Order_Lines = new List<Received_Supplier_Order_Line>()
            };

            _appContext.Received_Supplier_Orders.Add(receivedSupplierOrder);
            await _appContext.SaveChangesAsync();

            if (receivedSupplierOrder.Accepted)
            {
                foreach (var line in receiveOrderVm.Received_Supplier_Order_Lines)
                {
                    var product = await _appContext.Products.FindAsync(line.Product_ID);

                    // Debugging and Logging
                    Console.WriteLine($"Processing Product ID: {line.Product_ID}");

                    if (product == null)
                    {
                        Console.WriteLine($"Product ID {line.Product_ID} not found.");
                        return BadRequest($"Product ID {line.Product_ID} not found.");
                    }

                    product.Quantity += line.Received_Supplies_Quantity;
                    _appContext.Products.Update(product);

                    var receivedOrderLine = new Received_Supplier_Order_Line
                    {
                        Received_Supplier_Order_ID = receivedSupplierOrder.Received_Supplier_Order_ID,
                        Received_Supplies_Quantity = line.Received_Supplies_Quantity,
                        Supplier_Order_Line_ID = line.Supplier_Order_Line_ID,
                        Product_ID = line.Product_ID // Ensure this is set
                    };

                    _appContext.Received_Supplier_Order_Lines.Add(receivedOrderLine);
                }

                await _appContext.SaveChangesAsync();
            }

            return Ok(receivedSupplierOrder);
        }

        [HttpPost]
        [Route("UpdateSupplierOrderStatus")]
        public async Task<IActionResult> UpdateSupplierOrderStatus([FromBody] UpdateSupplierOrderStatusViewModel statusUpdateVm)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            // Fetch the specific supplier order entry
            var supplierOrder = await _appContext.Supplier_Orders
                .FirstOrDefaultAsync(o => o.Supplier_Order_ID == statusUpdateVm.Supplier_Order_ID);

            if (supplierOrder == null)
            {
                return BadRequest($"Supplier order with ID {statusUpdateVm.Supplier_Order_ID} not found.");
            }

            // Update the status based on the Accepted boolean
            supplierOrder.Status = statusUpdateVm.Status; // Ensure this is directly assigned

            // Save changes to the database
            await _appContext.SaveChangesAsync();

            return Ok(supplierOrder);
        }
    }
}
//models
public class Supplier_Order
{
    [Key]
    public int Supplier_Order_ID { get; set; }

    //[Required]
    public DateTime Date { get; set; }

    //[Required]
    public string? Supplier_Order_Details { get; set; }

    //[Required]
    public decimal Total_Price { get; set; }

    public int Status { get; set; }

    public int Supplier_ID { get; set; }

    [ForeignKey(nameof(Supplier_ID))]
    public Supplier Supplier { get; set; }

    public int Owner_ID { get; set; }

    [ForeignKey(nameof(Owner_ID))]
    public Owner Owner { get; set; }

    public ICollection<Supplier_Order_Line> Supplier_Order_Lines { get; set; }
}
public class Supplier_Order_Line
{
    [Key]
    public int Supplier_Order_Line_ID { get; set; }

    public int Supplier_Quantity { get; set; }


    public int Product_ID { get; set; }

    [ForeignKey(nameof(Product_ID))]

    public Product Product { get; set; }

    public decimal? Purchase_Price { get; set; } 

    public decimal? Unit_Price { get; set; } 

    public int Supplier_Order_ID { get; set; }

    [ForeignKey(nameof(Supplier_Order_ID))]
    public Supplier_Order Supplier_Order { get; set; } 
}
public class Received_Supplier_Order
{
    [Key]
    public int Received_Supplier_Order_ID { get; set; }

    [Required]
    public DateTime Supplies_Received_Date { get; set; }

    public bool Accepted { get; set; } // Indicates if the order was accepted

    public string? Discrepancies { get; set; }  // Nullable attribute for discrepancies

    public ICollection<Received_Supplier_Order_Line> Received_Supplier_Order_Lines { get; set; }
}
public class Received_Supplier_Order_Line
{
    [Key]
    public int Received_Supplier_Order_Line_ID { get; set; }

    public int Received_Supplier_Order_ID { get; set; }

    [ForeignKey(nameof(Received_Supplier_Order_ID))]

    public Received_Supplier_Order Received_Supplier_Order { get; set; }


    public int Supplier_Order_Line_ID { get; set; }

    [ForeignKey(nameof(Supplier_Order_Line_ID))]

    public Supplier_Order_Line Supplier_Order_Line { get; set; }
  

    public int Product_ID { get; set; }

    [ForeignKey(nameof(Product_ID))]

    public Product Product { get; set; }

    public int Received_Supplies_Quantity { get; set; }
}

//viewmodels
public class SupplierOrderViewModel
{
    public int Supplier_Order_ID { get; set; }
    public DateTime Date { get; set; }
    public string Supplier_Order_Details { get; set; }
    public decimal Total_Price { get; set; }
    public int Supplier_ID { get; set; }
    public string Supplier_Name { get; set; }
    public int Owner_ID { get; set; }
    public int Status { get; set; }
    public ICollection<SupplierOrderLineViewModel> OrderLines { get; set; }
}
public class SupplierOrderLineViewModel
{
    public int Supplier_Order_Line_ID { get; set; }
    public int Product_ID { get; set; }
    public string Product_Name { get; set; }
    public int Supplier_Quantity { get; set; }

    public decimal? Purchase_Price { get; set; }
}
public class UpdateSupplierOrderStatusViewModel
{
    public int Supplier_Order_ID { get; set; }
    public int Status { get; set; } // Boolean to indicate acceptance/rejection
}
public class ReceivedSupplierOrderViewModel
{
    public DateTime Supplies_Received_Date { get; set; }

    public bool? Accepted { get; set; } // Nullable bool to indicate acceptance/rejection

    public string? Discrepancies { get; set; }  // Nullable attribute for discrepancies

    public List<ReceivedSupplierOrderLineViewModel> Received_Supplier_Order_Lines { get; set; }
}

public class ReceivedSupplierOrderLineViewModel
{
    public int Product_ID { get; set; }
    public int Received_Supplies_Quantity { get; set; }
    public int Supplier_Order_Line_ID { get; set; }
}