using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using SIGCM2.Api.Authorization;
using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Common;
using SIGCM2.Application.Products.Prices;
using SIGCM2.Application.Products.Prices.AddPrice;
using SIGCM2.Application.Products.Prices.GetHistory;

namespace SIGCM2.Api.Controllers;

/// <summary>
/// PRD-003: ProductPrices historic pricing management.
/// Read endpoint at GET /api/v1/products/{id}/prices — requires 'catalogo:productos:gestionar'.
/// Write endpoint at POST /api/v1/admin/products/{id}/prices — requires 'catalogo:productos:gestionar'.
/// </summary>
[ApiController]
public sealed class ProductPricesController : ControllerBase
{
    private readonly IDispatcher _dispatcher;
    private readonly IValidator<AddProductPriceCommand> _addValidator;

    public ProductPricesController(
        IDispatcher dispatcher,
        IValidator<AddProductPriceCommand> addValidator)
    {
        _dispatcher = dispatcher;
        _addValidator = addValidator;
    }

    // ── READ endpoint ──────────────────────────────────────────────────────────

    /// <summary>
    /// Returns a paginated page of price history for a Product, ordered descending by PriceValidFrom.
    /// Defaults: page=1, pageSize=20. Clamping: page ≥ 1, pageSize ∈ [1, 100].
    /// Returns 200 with empty items if the product has no prices yet or page is beyond total.
    /// Returns 404 if the product does not exist.
    /// Returns 401 if not authenticated, 403 if missing 'catalogo:productos:gestionar' permission.
    /// </summary>
    [HttpGet("api/v1/products/{id:int}/prices")]
    [RequirePermission("catalogo:productos:gestionar")]
    [ProducesResponseType(typeof(PagedResult<ProductPriceDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetProductPrices(
        [FromRoute] int id,
        [FromQuery] int? page,
        [FromQuery] int? pageSize)
    {
        var query = new GetProductPricesQuery(
            ProductId: id,
            Page: page ?? 1,
            PageSize: pageSize ?? 20);
        var result = await _dispatcher.Send<GetProductPricesQuery, PagedResult<ProductPriceDto>>(query);
        return Ok(result);
    }

    // ── WRITE endpoint ─────────────────────────────────────────────────────────

    /// <summary>
    /// Adds a new price to a Product. Closes the current active price if one exists.
    /// PriceValidFrom must be >= today_AR and strictly greater than the active price's PriceValidFrom.
    /// Returns 201 Created with Location header pointing to GET /api/v1/products/{id}/prices.
    /// </summary>
    [HttpPost("api/v1/admin/products/{id:int}/prices")]
    [RequirePermission("catalogo:productos:gestionar")]
    [ProducesResponseType(typeof(AddProductPriceResponse), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> AddProductPrice(
        [FromRoute] int id,
        [FromBody] AddProductPriceRequest request)
    {
        var command = new AddProductPriceCommand(
            ProductId: id,
            Price: request.Price,
            PriceValidFrom: request.PriceValidFrom);

        var validation = await _addValidator.ValidateAsync(command);
        if (!validation.IsValid)
        {
            var errors = validation.Errors
                .GroupBy(e => e.PropertyName)
                .ToDictionary(g => g.Key, g => g.Select(e => e.ErrorMessage).ToArray());
            return BadRequest(new { errors });
        }

        var result = await _dispatcher.Send<AddProductPriceCommand, AddProductPriceResponse>(command);
        return CreatedAtAction(nameof(GetProductPrices), new { id }, result);
    }
}

// ── Request body record ───────────────────────────────────────────────────────

/// <summary>PRD-003: Add ProductPrice request body.</summary>
public sealed record AddProductPriceRequest(
    decimal Price,
    DateOnly PriceValidFrom);
