using System.Net;
using System.Text.Json;
using FlatRender.IdentitySvc.Models.Responses;

namespace FlatRender.IdentitySvc.Middleware;

public class ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger)
{
    private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
        var traceId = context.TraceIdentifier;

        var (status, code, message) = ex switch
        {
            KeyNotFoundException => (HttpStatusCode.NotFound, "NOT_FOUND", ex.Message),
            UnauthorizedAccessException => (HttpStatusCode.Unauthorized, "UNAUTHORIZED", ex.Message),
            InvalidOperationException => (HttpStatusCode.BadRequest, "INVALID_OPERATION", ex.Message),
            ArgumentException => (HttpStatusCode.BadRequest, "INVALID_ARGUMENT", ex.Message),
            NotImplementedException => (HttpStatusCode.NotImplemented, "NOT_IMPLEMENTED", ex.Message),
            _ => (HttpStatusCode.InternalServerError, "INTERNAL_ERROR", "An unexpected error occurred"),
        };

        if (status == HttpStatusCode.InternalServerError)
            logger.LogError(ex, "Unhandled exception {TraceId}", traceId);

        context.Response.StatusCode = (int)status;
        context.Response.ContentType = "application/json";

        var body = JsonSerializer.Serialize(
            new { error = new ApiError(code, message, null, traceId) },
            JsonOptions);

        await context.Response.WriteAsync(body);
    }
}
