using Femto.Common.Domain;
using Femto.Common.Logs;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.WebUtilities;

namespace Femto.Api.Middleware;

public class ExceptionMapperMiddleware(
    RequestDelegate next,
    IWebHostEnvironment env,
    ILogger<ExceptionMapperMiddleware> logger
)
{
    public async Task Invoke(HttpContext context, ProblemDetailsFactory problemDetailsFactory)
    {
        try
        {
            await next(context);

            if (context.Response.StatusCode >= 400)
            {
                logger.LogFailedRequest(
                    context.Request.Method,
                    context.Request.Path,
                    context.Response.StatusCode,
                    context.TraceIdentifier,
                    ReasonPhrases.GetReasonPhrase(context.Response.StatusCode)
                );
            }
        }
        catch (DomainError e)
        {
            context.Response.StatusCode = 400;
            context.Response.ContentType = "application/json";

            var problemDetails = problemDetailsFactory.CreateProblemDetails(
                context,
                statusCode: 400,
                title: "client error",
                detail: e.Message
            );

            logger.LogFailedRequest(
                e,
                context.Request.Method,
                context.Request.Path,
                context.Response.StatusCode,
                context.TraceIdentifier,
                e.Message
            );

            await context.Response.WriteAsJsonAsync(problemDetails);
        }
        catch (Exception e)
        {
            context.Response.StatusCode = 500;
            context.Response.ContentType = "application/json";
            var problemDetails = problemDetailsFactory.CreateProblemDetails(
                context,
                statusCode: 500,
                title: "server error error",
                detail: env.IsDevelopment() ? e.Message : "Something went wrong"
            );

            logger.LogFailedRequest(
                e,
                context.Request.Method,
                context.Request.Path,
                context.Response.StatusCode,
                context.TraceIdentifier,
                e.Message
            );

            await context.Response.WriteAsJsonAsync(problemDetails);
        }
        finally { }
    }
}
