using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PowderCoating.Core.Entities;
using PowderCoating.Core.Interfaces;
using PowderCoating.Shared.Constants;

namespace PowderCoating.Web.Controllers;

/// <summary>
/// Lightweight API endpoints consumed by the client-side item wizard.
/// Intentionally uses <c>CanManageJobs</c> (not <c>CanManageProducts</c>) so that
/// any user who can create quotes or jobs can also save items to the catalog directly
/// from the wizard without needing a separate catalog-management permission.
/// </summary>
[Authorize(Policy = AppConstants.Policies.CanManageJobs)]
public class ItemWizardController : Controller
{
    private readonly IUnitOfWork _unitOfWork;
    private readonly ITenantContext _tenantContext;
    private readonly ILogger<ItemWizardController> _logger;

    public ItemWizardController(IUnitOfWork unitOfWork, ITenantContext tenantContext,
        ILogger<ItemWizardController> logger)
    {
        _unitOfWork = unitOfWork;
        _tenantContext = tenantContext;
        _logger = logger;
    }

    /// <summary>
    /// Returns active catalog categories for the current company with their full hierarchy path
    /// (e.g. "Automotive > Wheels") so the wizard dropdown can distinguish categories that share
    /// the same name but sit under different parents. Paths are built in-memory after a single
    /// query — no extra round-trips needed since ParentCategoryId is a scalar field.
    /// </summary>
    [HttpGet]
    public async Task<IActionResult> GetCatalogCategories()
    {
        var companyId = _tenantContext.GetCurrentCompanyId();
        if (companyId == null) return Json(Array.Empty<object>());

        var cats = await _unitOfWork.CatalogCategories.FindAsync(
            c => c.CompanyId == companyId.Value && !c.IsDeleted);

        var lookup = cats.ToDictionary(c => c.Id);

        string BuildPath(PowderCoating.Core.Entities.CatalogCategory cat)
        {
            var parts = new System.Collections.Generic.List<string> { cat.Name };
            var current = cat;
            while (current.ParentCategoryId.HasValue &&
                   lookup.TryGetValue(current.ParentCategoryId.Value, out var parent))
            {
                parts.Insert(0, parent.Name);
                current = parent;
            }
            return string.Join(" > ", parts);
        }

        return Json(cats
            .Select(c => new { c.Id, Name = BuildPath(c) })
            .OrderBy(c => c.Name));
    }

    /// <summary>
    /// Creates a new catalog item from the item wizard's Save-to-Catalog step.
    /// Called via AJAX immediately when the user confirms the save — before the quote
    /// or job form is submitted — so the catalog item is saved even if the user later
    /// abandons the quote.
    /// </summary>
    [HttpPost]
    public async Task<IActionResult> SaveToCatalog([FromBody] SaveToCatalogRequest request)
    {
        try
        {
            var companyId = _tenantContext.GetCurrentCompanyId();
            if (companyId == null)
                return Json(new { ok = false, error = "No company context." });

            if (string.IsNullOrWhiteSpace(request.Name))
                return Json(new { ok = false, error = "Item name is required." });

            if (request.CategoryId <= 0)
                return Json(new { ok = false, error = "Please select a category." });

            var category = await _unitOfWork.CatalogCategories.GetByIdAsync(request.CategoryId);
            if (category == null || category.CompanyId != companyId.Value)
                return Json(new { ok = false, error = "Invalid category." });

            var item = new CatalogItem
            {
                CompanyId                  = companyId.Value,
                Name                       = request.Name.Trim(),
                Description                = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim(),
                CategoryId                 = request.CategoryId,
                DefaultPrice               = request.DefaultPrice,
                ApproximateArea            = request.ApproximateArea > 0 ? request.ApproximateArea : null,
                DefaultEstimatedMinutes    = request.DefaultEstimatedMinutes > 0 ? request.DefaultEstimatedMinutes : null,
                DefaultRequiresSandblasting = request.DefaultRequiresSandblasting,
                DefaultRequiresMasking     = request.DefaultRequiresMasking,
                IsActive                   = true,
                DisplayOrder               = 0
            };

            await _unitOfWork.CatalogItems.AddAsync(item);
            await _unitOfWork.CompleteAsync();

            _logger.LogInformation("Catalog item '{Name}' (id {Id}) created from item wizard by company {CompanyId}",
                item.Name, item.Id, companyId.Value);

            return Json(new { ok = true, id = item.Id, name = item.Name });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error saving catalog item from wizard");
            return Json(new { ok = false, error = "An error occurred saving the item. Please try again." });
        }
    }
}

public class SaveToCatalogRequest
{
    public string Name { get; set; } = string.Empty;
    public int CategoryId { get; set; }
    public decimal DefaultPrice { get; set; }
    public string? Description { get; set; }
    public decimal ApproximateArea { get; set; }
    public int DefaultEstimatedMinutes { get; set; }
    public bool DefaultRequiresSandblasting { get; set; }
    public bool DefaultRequiresMasking { get; set; }
}
