using System.Text.Json;
using Meezi.Core.Constants;
using Meezi.Core.Interfaces;
using Meezi.Infrastructure.Data;
using Meezi.Shared;

namespace Meezi.Admin.API.Middleware;

public class AdminTenantMiddleware
{
    private static readonly string[] PublicPrefixes =
    [
        "/api/admin/auth",
        "/health",
        "/swagger"
    ];

    private readonly RequestDelegate _next;

    public AdminTenantMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context, ITenantContext tenant)
    {
        if (IsPublicPath(context.Request.Path))
        {
            await _next(context);
            return;
        }

        if (context.User.Identity?.IsAuthenticated != true)
        {
            await WriteUnauthorizedAsync(context, "UNAUTHORIZED", "Authentication required.");
            return;
        }

        var actor = context.User.FindFirst(MeeziClaimTypes.Actor)?.Value;
        if (actor != MeeziActorKinds.SystemAdmin)
        {
            await WriteUnauthorizedAsync(context, "FORBIDDEN", "System admin access required.");
            return;
        }

        if (tenant is Infrastructure.Data.TenantContext scoped)
        {
            scoped.UserId = context.User.FindFirst("sub")?.Value
                ?? context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
            scoped.Language = context.User.FindFirst(MeeziClaimTypes.Language)?.Value ?? "fa";
            scoped.IsSystemAdmin = true;
        }

        await _next(context);
    }

    private static bool IsPublicPath(PathString path) =>
        PublicPrefixes.Any(p => path.StartsWithSegments(p, StringComparison.OrdinalIgnoreCase));

    private static async Task WriteUnauthorizedAsync(HttpContext context, string code, string message)
    {
        context.Response.StatusCode = StatusCodes.Status401Unauthorized;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsync(JsonSerializer.Serialize(new ApiResponse<object>(false, null, new ApiError(code, message))));
    }
}
