using System.Security.Claims;
using ZB.MOM.WW.Auth.AspNetCore;

namespace ZB.MOM.WW.MxGateway.Server.Security.Audit;

/// <summary>
/// HTTP-context-backed implementation of <see cref="IAuditActorAccessor"/> that reads the
/// dashboard operator's identity from the current <see cref="IHttpContextAccessor"/>.
/// </summary>
/// <remarks>
/// Claim resolution order:
/// <list type="number">
///   <item><see cref="ZbClaimTypes.Username"/> ("zb:username") — the canonical LDAP login name.</item>
///   <item><see cref="ClaimsPrincipal.Identity"/>.<see cref="System.Security.Principal.IIdentity.Name"/> — framework fallback (= <see cref="ZbClaimTypes.Name"/> = <see cref="ClaimTypes.Name"/> = display name).</item>
///   <item><see cref="ZbClaimTypes.Name"/> — explicit fallback matching the claim emitted by <c>DashboardAuthenticator.CreatePrincipal</c>.</item>
/// </list>
/// Returns <see langword="null"/> when there is no HTTP context or the user is not authenticated.
/// </remarks>
public sealed class HttpAuditActorAccessor(IHttpContextAccessor httpContextAccessor) : IAuditActorAccessor
{
    /// <inheritdoc />
    public string? CurrentActor
    {
        get
        {
            ClaimsPrincipal? user = httpContextAccessor.HttpContext?.User;
            if (user?.Identity?.IsAuthenticated != true)
            {
                return null;
            }

            // Prefer the canonical login-username claim (set by DashboardAuthenticator).
            string? username = user.FindFirstValue(ZbClaimTypes.Username);
            if (!string.IsNullOrWhiteSpace(username))
            {
                return username;
            }

            // Framework fallback: Identity.Name is driven by the ClaimsIdentity nameClaimType,
            // which DashboardAuthenticator sets to ZbClaimTypes.Name (= ClaimTypes.Name = display name).
            string? identityName = user.Identity?.Name;
            if (!string.IsNullOrWhiteSpace(identityName))
            {
                return identityName;
            }

            // Final explicit fallback — ZbClaimTypes.Name claim value directly.
            return user.FindFirstValue(ZbClaimTypes.Name);
        }
    }
}
