using System.Security.Claims;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Http;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Auth;

/// <summary>
/// Bridges ASP.NET Core cookie authentication with Blazor Server's auth state.
/// <para>
/// The cookie middleware validates and decrypts the cookie during the initial
/// HTTP request that establishes the Blazor circuit. This provider is registered
/// <c>Scoped</c>, so it is constructed within that request's DI scope while
/// <see cref="IHttpContextAccessor.HttpContext"/> is still valid. We snapshot
/// the authenticated principal <b>once</b> in the constructor and serve that
/// snapshot for the lifetime of the circuit.
/// </para>
/// <para>
/// We must NOT read <see cref="IHttpContextAccessor"/> on every
/// <see cref="GetAuthenticationStateAsync"/> call: for the
/// lifetime of a long-lived SignalR circuit <c>HttpContext</c> is <c>null</c>
/// (or, worse, a stale/foreign context), so a later re-evaluation —
/// e.g. <c>&lt;AuthorizeView&gt;</c> re-rendering — would otherwise see an
/// unauthenticated principal and render the wrong UI.
/// </para>
/// </summary>
public class CookieAuthenticationStateProvider : ServerAuthenticationStateProvider
{
    private readonly Task<AuthenticationState> _circuitAuthState;

    /// <summary>
    /// Snapshots the authenticated principal from the current HTTP context for use throughout the circuit lifetime.
    /// </summary>
    /// <param name="httpContextAccessor">Accessor used to read the initial HTTP context principal.</param>
    public CookieAuthenticationStateProvider(IHttpContextAccessor httpContextAccessor)
    {
        // Snapshot the principal at circuit-construction time. HttpContext is
        // valid here (initial HTTP request) and will not be afterwards.
        var user = httpContextAccessor.HttpContext?.User
            ?? new ClaimsPrincipal(new ClaimsIdentity());

        _circuitAuthState = Task.FromResult(new AuthenticationState(user));
    }

    /// <inheritdoc />
    public override Task<AuthenticationState> GetAuthenticationStateAsync()
        => _circuitAuthState;
}
