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

namespace KernelRecordsMVC.Controllers;

public class AdminController : Controller
{
    private readonly KernelRecordsContext _context;

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


    // ==========================================
    // ADMIN DASHBOARD
    // ==========================================

    [HttpGet]
    public IActionResult Index()
    {
        if (!IsAdmin())
            return Forbid();

        return View();
    }


    // ==========================================
    // UC008
    // NEW PRODUCT - GET
    // ==========================================

    [HttpGet]
    public IActionResult CreateProduct()
    {
        if (!IsProductManager())
            return Forbid();

        ViewBag.Releases = _context.Releases
            .OrderBy(x => x.Title)
            .ToList();

        return View(new CreateProductViewModel());
    }


    // ==========================================
    // UC008
    // NEW PRODUCT - POST
    // ==========================================

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult CreateProduct(
        CreateProductViewModel model)
    {
        if (!IsProductManager())
            return Forbid();

        if (!ModelState.IsValid)
        {
            LoadReleases();
            return View(model);
        }


        // Make sure the release actually exists.
        var release = _context.Releases
            .FirstOrDefault(x =>
                x.ReleaseId == model.ReleaseId);

        if (release == null)
        {
            ModelState.AddModelError(
                "ReleaseId",
                "The selected release does not exist.");

            LoadReleases();
            return View(model);
        }


        // Don't allow duplicate format for
        // the same release.
        var alreadyExists = _context.Products.Any(p =>
            p.ReleaseId == model.ReleaseId &&
            p.Format == model.Format);

        if (alreadyExists)
        {
            ModelState.AddModelError(
                "Format",
                "This release already has a product in this format.");

            LoadReleases();
            return View(model);
        }


        var product = new Product
        {
            ProductId = GetNextProductId(),

            ReleaseId = model.ReleaseId,

            Format = model.Format,

            Price = model.Price,

            ProductDescription =
                model.ProductDescription,

            Stock = model.Stock
        };


        _context.Products.Add(product);

        _context.SaveChanges();


        // Record the modification.
        CreateModification(
            ModificationType.CREATE,
            product.ProductId);


        TempData["Success"] =
            "Product created successfully.";


        return RedirectToAction(
            nameof(Index));
    }


    // ==========================================
    // HELPERS
    // ==========================================

    private bool IsAdmin()
    {
        return HttpContext.Session
            .GetString("Role") == "Admin";
    }


    private bool IsProductManager()
    {
        var role = HttpContext.Session
            .GetString("Role");

        var adminType = HttpContext.Session
            .GetString("AdminType");

        return role == "Admin" &&
               (adminType == "PRODUCT_MANAGER" ||
                adminType == "SUPER_ADMIN");
    }


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

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

        return null;
    }


    private long GetNextProductId()
    {
        var maxId = _context.Products
            .Select(x => (long?)x.ProductId)
            .Max();

        return (maxId ?? 0) + 1;
    }


    private void LoadReleases()
    {
        ViewBag.Releases = _context.Releases
            .OrderBy(x => x.Title)
            .ToList();
    }


    private void CreateModification(
        ModificationType type,
        long productId,
        decimal? discount = null)
    {
        var adminId = GetCurrentUserId();

        if (adminId == null)
            return;


        var modification = new Modification
        {
            ModificationId =
                GetNextModificationId(),

            AdminId = adminId.Value,

            DateModified = DateTime.Today,

            TypeOfModification = type,

            Discount = discount
        };


        _context.Modifications.Add(modification);

        _context.SaveChanges();


        var modificationProduct =
            new ModificationProduct
            {
                ModificationId =
                    modification.ModificationId,

                ProductId = productId
            };


        _context.ModificationProducts.Add(
            modificationProduct);

        _context.SaveChanges();
    }


    private long GetNextModificationId()
    {
        var maxId = _context.Modifications
            .Select(x => (long?)x.ModificationId)
            .Max();

        return (maxId ?? 0) + 1;
    }
    // ==========================================
// UC009
// MODIFY PRODUCT - GET
// ==========================================

    [HttpGet]
    public IActionResult EditProduct(long id)
    {
        if (!IsProductManager())
            return Forbid();

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

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

        var model = new EditProductViewModel
        {
            ProductId = product.ProductId,
            ReleaseId = product.ReleaseId,
            ReleaseTitle = product.Release.Title,
            Format = product.Format,
            Price = product.Price,
            ProductDescription = product.ProductDescription,
            Stock = product.Stock
        };

        return View(model);
    }
    // ==========================================
// UC009
// MODIFY PRODUCT - POST
// ==========================================

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult EditProduct(
    EditProductViewModel model)
{
    if (!IsProductManager())
        return Forbid();

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

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

    if (!ModelState.IsValid)
    {
        model.ReleaseTitle = product.Release.Title;
        model.ReleaseId = product.ReleaseId;
        model.Format = product.Format;

        return View(model);
    }


    // ==========================================
    // DISCOUNT
    // ==========================================

    if (model.ModificationType ==
        ModificationType.DISCOUNT)
    {
        if (!model.Discount.HasValue)
        {
            ModelState.AddModelError(
                "Discount",
                "Please enter a discount percentage.");

            model.ReleaseTitle = product.Release.Title;
            model.ReleaseId = product.ReleaseId;
            model.Format = product.Format;

            return View(model);
        }

        product.Price =
            product.Price *
            (1 - model.Discount.Value / 100m);
    }
    else
    {
        // ==========================================
        // NORMAL UPDATE
        // ==========================================

        product.Price = model.Price;

        product.ProductDescription =
            model.ProductDescription;

        product.Stock = model.Stock;
    }


    _context.SaveChanges();


    // ==========================================
    // RECORD MODIFICATION
    // ==========================================

    CreateModification(
        model.ModificationType,
        product.ProductId,
        model.Discount);


    TempData["Success"] =
        "Product modified successfully.";

    return RedirectToAction(nameof(Index));
}
[HttpGet]
public IActionResult Products()
{
    if (!IsProductManager())
        return Forbid();

    var products = _context.Products
        .Include(p => p.Release)
        .OrderBy(p => p.Release.Title)
        .ThenBy(p => p.Format)
        .ToList();

    return View(products);
}
}