using GestionIntegral.Api.Dtos.Contables;
using GestionIntegral.Api.Services.Contables;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

namespace GestionIntegral.Api.Controllers.Contables
{
    [Route("api/saldos")]
    [ApiController]
    [Authorize] // Requiere autenticación para todos los endpoints
    public class SaldosController : ControllerBase
    {
        private readonly ISaldoService _saldoService;
        private readonly ILogger<SaldosController> _logger;

        // Permiso para ver saldos. El ajuste manual es exclusivo de SuperAdmin (no se valida un permiso asignable).
        private const string PermisoVerSaldos = "CS001";


        public SaldosController(ISaldoService saldoService, ILogger<SaldosController> logger)
        {
            _saldoService = saldoService;
            _logger = logger;
        }

        private bool TienePermiso(string codAccRequerido)
        {
            if (User.IsInRole("SuperAdmin")) return true;
            return User.HasClaim(c => c.Type == "permission" && c.Value == codAccRequerido);
        }
        private int? GetCurrentUserId()
        {
            if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
            _logger.LogWarning("No se pudo obtener el UserId del token JWT en SaldosController.");
            return null;
        }

        // GET: api/saldos
        [HttpGet]
        [ProducesResponseType(typeof(IEnumerable<SaldoGestionDto>), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status403Forbidden)]
        public async Task<IActionResult> GetSaldosGestion(
            [FromQuery] string? destino, 
            [FromQuery] int? idDestino, 
            [FromQuery] int? idEmpresa)
        {
            if (!TienePermiso(PermisoVerSaldos)) // Usar el nuevo permiso
            {
                _logger.LogWarning("Acceso denegado a GetSaldosGestion para Usuario ID {userId}", GetCurrentUserId() ?? 0);
                return Forbid();
            }

            try
            {
                var saldos = await _saldoService.ObtenerSaldosParaGestionAsync(destino, idDestino, idEmpresa);
                return Ok(saldos);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error al obtener saldos para gestión.");
                return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al obtener saldos.");
            }
        }

        // POST: api/saldos/ajustar
        [HttpPost("ajustar")]
        [ProducesResponseType(typeof(SaldoGestionDto), StatusCodes.Status200OK)] // Devuelve el saldo actualizado
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        [ProducesResponseType(StatusCodes.Status403Forbidden)] // Solo SuperAdmin o con permiso específico
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<IActionResult> AjustarSaldoManualmente([FromBody] AjusteSaldoRequestDto ajusteDto)
        {
            // El ajuste manual de saldo es operación crítica: solo SuperAdmin. No se admite vía permiso asignable.
            if (!User.IsInRole("SuperAdmin"))
            {
                 _logger.LogWarning("Intento no autorizado de ajustar saldo por Usuario ID {userId}", GetCurrentUserId() ?? 0);
                return Forbid("Solo SuperAdmin puede ajustar saldos manualmente.");
            }

            if (!ModelState.IsValid) return BadRequest(ModelState);

            var idUsuario = GetCurrentUserId();
            if (idUsuario == null) return Unauthorized("No se pudo identificar al usuario.");

            try
            {
                var (exito, error, saldoActualizado) = await _saldoService.RealizarAjusteManualSaldoAsync(ajusteDto, idUsuario.Value);
                if (!exito)
                {
                    if (error != null && error.Contains("No se encontró un saldo existente"))
                        return NotFound(new { message = error });
                    return BadRequest(new { message = error ?? "Error desconocido al ajustar el saldo." });
                }
                return Ok(saldoActualizado);
            }
            catch (BloqueoPorPeriodoCerradoException)
            {
                throw;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error crítico al ajustar saldo manualmente.");
                return StatusCode(StatusCodes.Status500InternalServerError, "Error interno al procesar el ajuste de saldo.");
            }
        }
    }
}