using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SIGCM2.Api.Authorization;
using SIGCM2.Application.Abstractions;
using SIGCM2.Application.Common;
using SIGCM2.Application.ProductTypes.Create;
using SIGCM2.Application.ProductTypes.Deactivate;
using SIGCM2.Application.ProductTypes.GetById;
using SIGCM2.Application.ProductTypes.List;
using SIGCM2.Application.ProductTypes.Update;

namespace SIGCM2.Api.Controllers;

/// <summary>
/// PRD-001: ProductType catalog management.
/// Read endpoints at /api/v1/product-types — require authentication (any role).
/// Write endpoints at /api/v1/admin/product-types — require 'catalogo:tipos:gestionar'.
/// </summary>
[ApiController]
public sealed class ProductTypesController : ControllerBase
{
    private readonly IDispatcher _dispatcher;
    private readonly IValidator<CreateProductTypeCommand> _createValidator;
    private readonly IValidator<UpdateProductTypeCommand> _updateValidator;

    public ProductTypesController(
        IDispatcher dispatcher,
        IValidator<CreateProductTypeCommand> createValidator,
        IValidator<UpdateProductTypeCommand> updateValidator)
    {
        _dispatcher = dispatcher;
        _createValidator = createValidator;
        _updateValidator = updateValidator;
    }

    // ── READ endpoints ─────────────────────────────────────────────────────────

    /// <summary>Returns a paginated list of ProductTypes. Requires authentication.</summary>
    [HttpGet("api/v1/product-types")]
    [Authorize]
    [ProducesResponseType(typeof(PagedResult<ProductTypeListItemDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> ListProductTypes(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] bool? activo = true,
        [FromQuery] string? search = null)
    {
        var query = new ListProductTypesQuery(page, pageSize, activo, search);
        var result = await _dispatcher.Send<ListProductTypesQuery, PagedResult<ProductTypeListItemDto>>(query);
        return Ok(result);
    }

    /// <summary>Returns a single ProductType by id. Requires authentication.</summary>
    [HttpGet("api/v1/product-types/{id:int}")]
    [Authorize]
    [ProducesResponseType(typeof(ProductTypeDetailDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetProductTypeById([FromRoute] int id)
    {
        var query = new GetProductTypeByIdQuery(id);
        var result = await _dispatcher.Send<GetProductTypeByIdQuery, ProductTypeDetailDto>(query);
        return Ok(result);
    }

    // ── WRITE endpoints ────────────────────────────────────────────────────────

    /// <summary>Creates a new ProductType. Requires catalogo:tipos:gestionar.</summary>
    [HttpPost("api/v1/admin/product-types")]
    [RequirePermission("catalogo:tipos:gestionar")]
    [ProducesResponseType(typeof(ProductTypeCreatedDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> CreateProductType([FromBody] CreateProductTypeRequest request)
    {
        var command = new CreateProductTypeCommand(
            Nombre: request.Nombre ?? string.Empty,
            HasDuration: request.HasDuration,
            RequiresText: request.RequiresText,
            RequiresCategory: request.RequiresCategory,
            IsBundle: request.IsBundle,
            AllowImages: request.AllowImages,
            MaxImages: request.MaxImages,
            MaxImageSizeMB: request.MaxImageSizeMB,
            MaxImageWidth: request.MaxImageWidth,
            MaxImageHeight: request.MaxImageHeight);

        var validation = await _createValidator.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<CreateProductTypeCommand, ProductTypeCreatedDto>(command);
        return CreatedAtAction(nameof(GetProductTypeById), new { id = result.Id }, result);
    }

    /// <summary>Updates a ProductType. Requires catalogo:tipos:gestionar.</summary>
    [HttpPut("api/v1/admin/product-types/{id:int}")]
    [RequirePermission("catalogo:tipos:gestionar")]
    [ProducesResponseType(typeof(ProductTypeUpdatedDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> UpdateProductType([FromRoute] int id, [FromBody] UpdateProductTypeRequest request)
    {
        var command = new UpdateProductTypeCommand(
            Id: id,
            Nombre: request.Nombre ?? string.Empty,
            HasDuration: request.HasDuration,
            RequiresText: request.RequiresText,
            RequiresCategory: request.RequiresCategory,
            IsBundle: request.IsBundle,
            AllowImages: request.AllowImages,
            MaxImages: request.MaxImages,
            MaxImageSizeMB: request.MaxImageSizeMB,
            MaxImageWidth: request.MaxImageWidth,
            MaxImageHeight: request.MaxImageHeight);

        var validation = await _updateValidator.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<UpdateProductTypeCommand, ProductTypeUpdatedDto>(command);
        return Ok(result);
    }

    /// <summary>Soft-deletes (deactivates) a ProductType. Requires catalogo:tipos:gestionar.</summary>
    [HttpDelete("api/v1/admin/product-types/{id:int}")]
    [RequirePermission("catalogo:tipos:gestionar")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> DeactivateProductType([FromRoute] int id)
    {
        var command = new DeactivateProductTypeCommand(id);
        await _dispatcher.Send<DeactivateProductTypeCommand, ProductTypeStatusDto>(command);
        return NoContent();
    }
}

// ── Request body records ──────────────────────────────────────────────────────

/// <summary>PRD-001: Create ProductType request body.</summary>
public sealed record CreateProductTypeRequest(
    string? Nombre,
    bool HasDuration = false,
    bool RequiresText = false,
    bool RequiresCategory = false,
    bool IsBundle = false,
    bool AllowImages = false,
    int? MaxImages = null,
    decimal? MaxImageSizeMB = null,
    int? MaxImageWidth = null,
    int? MaxImageHeight = null);

/// <summary>PRD-001: Update ProductType request body.</summary>
public sealed record UpdateProductTypeRequest(
    string? Nombre,
    bool HasDuration = false,
    bool RequiresText = false,
    bool RequiresCategory = false,
    bool IsBundle = false,
    bool AllowImages = false,
    int? MaxImages = null,
    decimal? MaxImageSizeMB = null,
    int? MaxImageWidth = null,
    int? MaxImageHeight = null);
