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

namespace SIGCM2.Api.Controllers;

/// <summary>
/// ADM-001: Seccion management endpoints at /api/v1/admin/secciones.
/// All endpoints require permission 'administracion:secciones:gestionar'.
/// </summary>
[ApiController]
[Route("api/v1/admin/secciones")]
public sealed class SeccionesController : ControllerBase
{
    private readonly IDispatcher _dispatcher;
    private readonly IValidator<CreateSeccionCommand> _createValidator;
    private readonly IValidator<UpdateSeccionCommand> _updateValidator;

    public SeccionesController(
        IDispatcher dispatcher,
        IValidator<CreateSeccionCommand> createValidator,
        IValidator<UpdateSeccionCommand> updateValidator)
    {
        _dispatcher = dispatcher;
        _createValidator = createValidator;
        _updateValidator = updateValidator;
    }

    /// <summary>Creates a new seccion. Requires administracion:secciones:gestionar.</summary>
    [HttpPost]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(typeof(SeccionCreatedDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> CreateSeccion([FromBody] CreateSeccionRequest request)
    {
        var command = new CreateSeccionCommand(
            MedioId: request.MedioId ?? 0,
            Codigo: request.Codigo ?? string.Empty,
            Nombre: request.Nombre ?? string.Empty,
            Tipo: request.Tipo ?? string.Empty);

        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<CreateSeccionCommand, SeccionCreatedDto>(command);
        return CreatedAtAction(nameof(GetSeccionById), new { id = result.Id }, result);
    }

    /// <summary>Lists secciones with optional filters and pagination.</summary>
    [HttpGet]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(typeof(PagedResult<SeccionListItemDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    public async Task<IActionResult> ListSecciones(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] int? medioId = null,
        [FromQuery] string? tipo = null,
        [FromQuery] bool? activo = null,
        [FromQuery] string? q = null)
    {
        if (page < 1) return BadRequest(new { error = "page must be >= 1" });
        if (pageSize < 1) return BadRequest(new { error = "pageSize must be >= 1" });

        var query = new ListSeccionesQuery(page, pageSize, medioId, tipo, activo, q);
        var result = await _dispatcher.Send<ListSeccionesQuery, PagedResult<SeccionListItemDto>>(query);
        return Ok(result);
    }

    /// <summary>Gets a single seccion by id.</summary>
    [HttpGet("{id:int}")]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(typeof(SeccionDetailDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetSeccionById([FromRoute] int id)
    {
        var query = new GetSeccionByIdQuery(id);
        var result = await _dispatcher.Send<GetSeccionByIdQuery, SeccionDetailDto>(query);
        return Ok(result);
    }

    /// <summary>Updates a seccion's editable fields.</summary>
    [HttpPut("{id:int}")]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(typeof(SeccionUpdatedDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> UpdateSeccion([FromRoute] int id, [FromBody] UpdateSeccionRequest request)
    {
        var command = new UpdateSeccionCommand(
            Id: id,
            Nombre: request.Nombre ?? string.Empty,
            Tipo: request.Tipo ?? string.Empty);

        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<UpdateSeccionCommand, SeccionUpdatedDto>(command);
        return Ok(result);
    }

    /// <summary>Deactivates a seccion (idempotent).</summary>
    [HttpPost("{id:int}/deactivate")]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> DeactivateSeccion([FromRoute] int id)
    {
        var command = new DeactivateSeccionCommand(id);
        await _dispatcher.Send<DeactivateSeccionCommand, SeccionStatusDto>(command);
        return NoContent();
    }

    /// <summary>Reactivates a seccion (idempotent).</summary>
    [HttpPost("{id:int}/reactivate")]
    [RequirePermission("administracion:secciones:gestionar")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> ReactivateSeccion([FromRoute] int id)
    {
        var command = new ReactivateSeccionCommand(id);
        await _dispatcher.Send<ReactivateSeccionCommand, SeccionStatusDto>(command);
        return NoContent();
    }
}

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

/// <summary>ADM-001: Create seccion request body.</summary>
public sealed record CreateSeccionRequest(
    int? MedioId,
    string? Codigo,
    string? Nombre,
    string? Tipo);

/// <summary>ADM-001: Update seccion request body.</summary>
public sealed record UpdateSeccionRequest(
    string? Nombre,
    string? Tipo);
