using Microsoft.AspNetCore.Authentication;
using System.Security.Claims;

namespace foodmarket.Api.Infrastructure.Tenancy;

/// <summary>В режиме «открыть как…» (SuperAdmin + X-Org-Override) сам
/// SuperAdmin не имеет роли Admin/Storekeeper/Cashier, потому что эти
/// роли — атрибуты сотрудника тенанта. Без трансформации claim'ов все
/// мутации, защищённые <c>[Authorize(Roles="Admin,Storekeeper")]</c>,
/// отшиваются 403 даже когда <see cref="ReadonlyOverrideMiddleware"/>
/// разрешил мутацию (edit-mode с X-Org-Override-Reason ≥ 10 символов).
///
/// Здесь мы временно (на текущий request) добавляем SuperAdmin'у полный
/// набор tenant-ролей, чтобы он мог пройти атрибуты-гарды контроллеров.
/// Изоляция и аудит остаются: query filter всё равно скоупится на
/// X-Org-Override, а <see cref="SuperAdminEditAuditFilter"/> пишет запись
/// в super_admin_audit_log с reason и diff'ом.
///
/// Срабатывает только если:
///   - User имеет роль SuperAdmin,
///   - запрос содержит заголовок X-Org-Override.
/// На GET-запросах (read-only override) тоже работает — это безопасно,
/// потому что мутации остаются за middleware-гардом.</summary>
public class SuperAdminOverrideClaimsTransformer : IClaimsTransformation
{
    private readonly IHttpContextAccessor _accessor;

    public SuperAdminOverrideClaimsTransformer(IHttpContextAccessor accessor)
        => _accessor = accessor;

    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var ctx = _accessor.HttpContext;
        if (ctx is null) return Task.FromResult(principal);

        var isSuper = principal.IsInRole(HttpContextTenantContext.SuperAdminRole);
        var hasOverride = ctx.Request.Headers.ContainsKey(HttpContextTenantContext.OrgOverrideHeader);
        if (!isSuper || !hasOverride) return Task.FromResult(principal);

        // Не клонируем — IClaimsTransformation вызывается на каждый запрос,
        // принципал и так свежий. Мутируем первый identity.
        var identity = principal.Identities.FirstOrDefault(i => i.IsAuthenticated);
        if (identity is null) return Task.FromResult(principal);

        foreach (var role in TenantRolesForOverride)
        {
            if (!principal.IsInRole(role))
                identity.AddClaim(new Claim(identity.RoleClaimType, role));
        }

        return Task.FromResult(principal);
    }

    private static readonly string[] TenantRolesForOverride =
    [
        "Admin", "Storekeeper", "Cashier",
    ];
}
