using System.Security.Claims;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.Security;
using ZB.MOM.WW.ScadaBridge.Security.Auth;
using Xunit;

namespace ZB.MOM.WW.ScadaBridge.Security.Tests;

public class AutoLoginAuthenticationHandlerTests
{
    /// <summary>
    /// Minimal <see cref="IOptionsMonitor{T}"/> stub for the scheme options the base
    /// <see cref="AuthenticationHandler{TOptions}"/> resolves during InitializeAsync. This
    /// test project deliberately carries no mocking library, so the seam is hand-rolled.
    /// </summary>
    private sealed class StubOptionsMonitor : IOptionsMonitor<AuthenticationSchemeOptions>
    {
        private readonly AuthenticationSchemeOptions _value = new();
        public AuthenticationSchemeOptions CurrentValue => _value;
        public AuthenticationSchemeOptions Get(string? name) => _value;
        public IDisposable? OnChange(Action<AuthenticationSchemeOptions, string?> listener) => null;
    }

    private static async Task<AutoLoginAuthenticationHandler> CreateAsync(string user = "multi-role")
    {
        var schemeOptions = new StubOptionsMonitor();
        var opts = Options.Create(new AuthDisableLoginOptions { DisableLogin = true, User = user });

        var handler = new AutoLoginAuthenticationHandler(
            schemeOptions, NullLoggerFactory.Instance, UrlEncoder.Default, opts, TimeProvider.System);

        await handler.InitializeAsync(
            new AuthenticationScheme(
                CookieAuthenticationDefaults.AuthenticationScheme, null, typeof(AutoLoginAuthenticationHandler)),
            new DefaultHttpContext());
        return handler;
    }

    [Fact]
    public async Task Authenticate_GrantsAllRoles_SystemWide_AsConfiguredUser()
    {
        var handler = await CreateAsync("multi-role");
        var result = await handler.AuthenticateAsync();

        Assert.True(result.Succeeded);
        var p = result.Principal!;
        Assert.True(p.Identity!.IsAuthenticated);  // first gate checked by [Authorize] + Blazor AuthenticationStateProvider
        Assert.Equal("multi-role", p.Identity!.Name);
        foreach (var role in Roles.All)
            Assert.True(p.IsInRole(role), $"expected role {role}");
        Assert.Empty(p.FindAll(JwtTokenService.SiteIdClaimType)); // system-wide => no scope claims
    }

    [Fact]
    public async Task Authenticate_BlankUser_FallsBackToMultiRole()
    {
        var handler = await CreateAsync("   ");
        var result = await handler.AuthenticateAsync();
        Assert.Equal("multi-role", result.Principal!.Identity!.Name);
    }

    [Fact]
    public async Task SignInAndSignOut_AreNoOps_DoNotThrow()
    {
        var handler = await CreateAsync();
        await handler.SignInAsync(new ClaimsPrincipal(), null);
        await handler.SignOutAsync(null);
    }
}
