﻿using Microsoft.AspNetCore.Http;

namespace KernelRecordsMVC.Controllers;

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using KernelRecordsMVC.Data;
using KernelRecordsMVC.Models;
using KernelRecordsMVC.Domain.Enums;
using KernelRecordsMVC.Application.ViewModels;

public class OrderController : Controller
{
    private readonly KernelRecordsContext _context;

    public OrderController(KernelRecordsContext context)
    {
        _context = context;
    }


    // ==========================================
    // ADD PRODUCT TO ORDER
    // UC007
    // ==========================================

    [HttpGet]
    public IActionResult AddProduct(long id)
    {
        var userId = GetUserId();

        if (userId == null)
            return RedirectToAction(
                "Login",
                "Account");

        var product = _context.Products
            .Include(p => p.Release)
            .FirstOrDefault(p => p.ProductId == id);

        if (product == null)
            return NotFound();

        if (product.Stock <= 0)
        {
            TempData["Error"] =
                "This product is currently out of stock.";

            return RedirectToAction(
                "Details",
                "Release",
                new { id = product.ReleaseId });
        }


        // Find an existing pending order.
        var order = _context.Orders
            .Include(o => o.OrderProducts)
            .FirstOrDefault(o =>
                o.UserId == userId.Value &&
                o.Status == OrderStatusType.PENDING);


        // If there is no pending order, create one.
        if (order == null)
        {
            order = new Order
            {
                OrderId = GetNextOrderId(),
                UserId = userId.Value,

                // The actual payment method will be
                // selected during checkout.
                PaymentMethod = PaymentMethodType.CARD,

                PurchaseDate = DateTime.Today,

                PointsEarned = 0,

                PointsUsed = null,

                Status = OrderStatusType.PENDING
            };

            _context.Orders.Add(order);

            _context.SaveChanges();
        }


        // Check whether product is already in cart.
        var existingItem = order.OrderProducts
            .FirstOrDefault(x =>
                x.ProductId == product.ProductId);


        if (existingItem != null)
        {
            if (existingItem.Quantity + 1 >
                product.Stock)
            {
                TempData["Error"] =
                    "There is not enough stock available.";

                return RedirectToAction(
                    "Details",
                    "Release",
                    new { id = product.ReleaseId });
            }

            existingItem.Quantity++;
        }
        else
        {
            var orderProduct = new OrderProduct
            {
                OrderId = order.OrderId,

                ProductId = product.ProductId,

                PriceAtPurchase = product.Price,

                Quantity = 1
            };

            _context.OrderProducts.Add(orderProduct);
        }

        _context.SaveChanges();


        return RedirectToAction(nameof(Cart));
    }


    // ==========================================
    // CART
    // ==========================================

    [HttpGet]
    public IActionResult Cart()
    {
        var userId = GetUserId();

        if (userId == null)
        {
            return RedirectToAction(
                "Login",
                "Account");
        }


        var order = _context.Orders
            .Include(o => o.OrderProducts)
                .ThenInclude(op => op.Product)
                    .ThenInclude(p => p.Release)
            .FirstOrDefault(o =>
                o.UserId == userId.Value &&
                o.Status == OrderStatusType.PENDING);


        var viewModel = new CartViewModel();


        if (order != null)
        {
            viewModel.Items = order.OrderProducts
                .Select(op => new CartItemViewModel
                {
                    ProductId = op.ProductId,

                    ReleaseId =
                        op.Product.ReleaseId,

                    ReleaseTitle =
                        op.Product.Release.Title,

                    Format =
                        op.Product.Format.ToString(),

                    Price =
                        op.PriceAtPurchase,

                    Quantity =
                        op.Quantity,

                    Stock =
                        op.Product.Stock
                })
                .ToList();
        }


        return View(viewModel);
    }


    // ==========================================
    // REMOVE PRODUCT
    // ==========================================

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult RemoveProduct(long id)
    {
        var userId = GetUserId();

        if (userId == null)
            return RedirectToAction(
                "Login",
                "Account");


        var item = _context.OrderProducts
            .Include(x => x.Order)
            .FirstOrDefault(x =>
                x.ProductId == id &&
                x.Order.UserId == userId.Value &&
                x.Order.Status ==
                    OrderStatusType.PENDING);


        if (item != null)
        {
            _context.OrderProducts.Remove(item);
            _context.SaveChanges();
        }


        return RedirectToAction(nameof(Cart));
    }


    // ==========================================
    // UPDATE QUANTITY
    // ==========================================

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult UpdateQuantity(
        long id,
        long quantity)
    {
        var userId = GetUserId();

        if (userId == null)
            return RedirectToAction(
                "Login",
                "Account");


        if (quantity <= 0)
        {
            return RemoveProduct(id);
        }


        var item = _context.OrderProducts
            .Include(x => x.Order)
            .Include(x => x.Product)
            .FirstOrDefault(x =>
                x.ProductId == id &&
                x.Order.UserId == userId.Value &&
                x.Order.Status ==
                    OrderStatusType.PENDING);


        if (item == null)
            return NotFound();


        if (quantity > item.Product.Stock)
        {
            TempData["Error"] =
                "The requested quantity exceeds available stock.";

            return RedirectToAction(nameof(Cart));
        }


        item.Quantity = quantity;

        _context.SaveChanges();


        return RedirectToAction(nameof(Cart));
    }


    // ==========================================
    // USER ID
    // ==========================================

    private long? GetUserId()
    {
        var value =
            HttpContext.Session.GetString("UserId");

        if (long.TryParse(value, out var userId))
            return userId;

        return null;
    }


    // ==========================================
    // ORDER ID
    // ==========================================

    private long GetNextOrderId()
    {
        var maxId = _context.Orders
            .Select(x => (long?)x.OrderId)
            .Max();

        return (maxId ?? 0) + 1;
    }
}