using GestionIntegral.Api.Services.Contables;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Text.Json;
using System.Threading.Tasks;

namespace GestionIntegral.Api.Middleware
{
    // Centraliza el mapeo de excepciones semánticas a HTTP responses con cuerpo JSON estandarizado.
    // Va PRIMERO en el pipeline para catchear cualquier excepción que escape de los controllers/services.
    public class ExceptionHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<ExceptionHandlerMiddleware> _logger;

        private static readonly JsonSerializerOptions JsonOptions = new()
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        public ExceptionHandlerMiddleware(RequestDelegate next, ILogger<ExceptionHandlerMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (BloqueoPorPeriodoCerradoException ex)
            {
                _logger.LogWarning(
                    "Bloqueo por período cerrado: cierre #{IdCierre} FechaCorte={FechaCorte:yyyy-MM-dd}. Path={Path}",
                    ex.IdCierre, ex.FechaCorte, context.Request.Path);

                await WriteJsonAsync(context, StatusCodes.Status409Conflict, new
                {
                    codigo = "PERIODO_CERRADO_BLOQUEO_OPERACION",
                    mensaje = ex.Message,
                    idCierre = ex.IdCierre,
                    fechaCorte = ex.FechaCorte.ToString("yyyy-MM-dd")
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Excepción no manejada. Path={Path}", context.Request.Path);

                await WriteJsonAsync(context, StatusCodes.Status500InternalServerError, new
                {
                    codigo = "ERROR_INTERNO",
                    mensaje = "Ocurrió un error inesperado al procesar la solicitud."
                });
            }
        }

        private static Task WriteJsonAsync(HttpContext context, int statusCode, object body)
        {
            if (context.Response.HasStarted)
            {
                // Si los headers ya se enviaron no podemos re-escribir el response. Solo loguear y salir.
                return Task.CompletedTask;
            }
            context.Response.Clear();
            context.Response.StatusCode = statusCode;
            context.Response.ContentType = "application/json; charset=utf-8";
            return context.Response.WriteAsync(JsonSerializer.Serialize(body, JsonOptions));
        }
    }
}
