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

namespace KernelRecordsMVC.Web.Controllers;

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


        using var transaction =
            _context.Database.BeginTransaction();

        try
        {
            var order = _context.Orders
                .Include(o => o.OrderProducts)
                .FirstOrDefault(o =>
                    o.UserId == userId.Value &&
                    o.Status == OrderStatusType.PENDING);
            
            if (order == null)
            {
                order = new Order
                {
                    UserId = userId.Value,
                    PaymentMethod = PaymentMethodType.CARD,
                    PurchaseDate = DateTime.Today,
                    PointsEarned = 0,
                    PointsUsed = null,
                    Status = OrderStatusType.PENDING
                };

                _context.Orders.Add(order);

                _context.SaveChanges();
            }

            
            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.";

                    transaction.Rollback();

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

                existingItem.Quantity++;
            }
            else
            {
                var discount = _context.ModificationProducts
                    .Include(mp => mp.Modification)
                    .Where(mp =>
                        mp.ProductId == product.ProductId &&
                        mp.Modification.TypeOfModification ==
                        ModificationType.DISCOUNT &&
                        mp.Modification.Discount.HasValue &&
                        mp.Modification.Discount.Value > 0)
                    .Select(mp => mp.Modification)
                    .OrderByDescending(m => m.DateModified)
                    .FirstOrDefault();


                var priceAtPurchase = product.Price;

                if (discount != null)
                {
                    priceAtPurchase =
                        product.Price -
                        (
                            product.Price *
                            discount.Discount!.Value /
                            100m
                        );

                    priceAtPurchase =
                        Math.Round(
                            priceAtPurchase,
                            2);
                }


                var orderProduct = new OrderProduct
                {
                    OrderId = order.OrderId,

                    ProductId =
                        product.ProductId,

                    PriceAtPurchase =
                        priceAtPurchase,

                    Quantity = 1
                };

                _context.OrderProducts.Add(orderProduct);
            }


            _context.SaveChanges();

            transaction.Commit();


            return RedirectToAction(nameof(Cart));
        }
        catch
        {
            transaction.Rollback();
            throw;
        }
    }


    // ==========================================
    // 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,

                    CoverPhoto =
                        op.Product.Release.CoverPhoto
                })
                .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 userId =
            HttpContext.Session.GetInt32("UserId");

        if (userId.HasValue)
            return userId.Value;

        return null;
    }
}