using System.Reflection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Pages;
using ZB.MOM.WW.Secrets.Ui;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;

/// <summary>
///     Pins the host-side wiring that makes <c>/admin/secrets</c> interactive (lmxopcua#483).
///     This host's router is static with per-page <c>@rendermode</c> opt-in; routing straight to
///     the Secrets.Ui RCL's routable page rendered it with no circuit — the page displayed but
///     every <c>@onclick</c> was dead, and nothing failed. The fix is a wrapper page in this
///     assembly that owns the route and carries the render mode. Razor directives compile to
///     class-level attributes, so a metadata scan is authoritative (same technique as
///     <c>PageAuthorizationGuardTests</c>; the repo has no bUnit).
/// </summary>
public class SecretsPageWiringTests
{
    /// <summary>
    ///     THE #483 regression pin: without a render mode this host serves the page as static SSR
    ///     and it silently loses all interactivity.
    /// </summary>
    [Fact]
    public void Wrapper_declares_the_InteractiveServer_render_mode()
    {
        var mode = typeof(SecretsAdmin).GetCustomAttributes<RenderModeAttribute>(inherit: false)
            .SingleOrDefault();

        mode.ShouldNotBeNull(
            "/admin/secrets lost its @rendermode — in this host's static router that renders a " +
            "dead page (displays, but no circuit and every @onclick inert), exactly lmxopcua#483");
        mode.Mode.ShouldBeOfType<InteractiveServerRenderMode>();
    }

    /// <summary>
    ///     The wrapper must shadow the RCL page's route exactly — if Secrets.Ui ever moves its
    ///     page, the wrapper must move with it or the nav rail and bookmarks split from the RCL.
    /// </summary>
    [Fact]
    public void Wrapper_owns_the_same_route_as_the_RCL_page()
    {
        string[] wrapper = [.. typeof(SecretsAdmin).GetCustomAttributes<RouteAttribute>(inherit: false).Select(r => r.Template)];
        string[] rcl = [.. typeof(SecretsPage).GetCustomAttributes<RouteAttribute>(inherit: false).Select(r => r.Template)];

        wrapper.ShouldBe(["/admin/secrets"]);
        wrapper.ShouldBe(rcl, "the wrapper must track the RCL page's route exactly");
    }

    /// <summary>
    ///     The router enforces [Authorize] only on the routed component — which is now the wrapper,
    ///     with the RCL page rendered as a plain child whose own attribute is inert. The wrapper
    ///     must therefore re-state the RCL page's policy verbatim, or the fix silently widens access.
    /// </summary>
    [Fact]
    public void Wrapper_restates_the_RCL_pages_authorization_policy()
    {
        var wrapper = typeof(SecretsAdmin).GetCustomAttributes<AuthorizeAttribute>(inherit: false).Single();
        var rcl = typeof(SecretsPage).GetCustomAttributes<AuthorizeAttribute>(inherit: false).Single();

        wrapper.Policy.ShouldBe(SecretsAuthorization.ManagePolicy);
        wrapper.Policy.ShouldBe(rcl.Policy, "the wrapper must enforce exactly what the RCL page declares");
    }
}
