using Bunit;
using Microsoft.AspNetCore.Components;
using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Shared;

/// <summary>
/// Accessibility regression tests.
/// Locks the a11y attributes on TreeView chevron toggles and the
/// ToastNotification live-region container against future regressions.
/// </summary>
public class AccessibilityTests : BunitContext
{
    // ── TreeView harness (mirrors TreeViewTests setup) ─────────────────────────

    private record TestNode(string Key, string Label, List<TestNode> Children);

    private static List<TestNode> BranchRoots() => new()
    {
        new("root-1", "Root One", new()
        {
            new("child-1", "Child One", new()),
        }),
        new("leaf-1", "Leaf One", new()),
    };

    private IRenderedComponent<TreeView<TestNode>> RenderTreeView(List<TestNode>? items = null)
    {
        return Render<TreeView<TestNode>>(parameters =>
        {
            parameters
                .Add(p => p.Items, items ?? BranchRoots())
                .Add(p => p.ChildrenSelector, n => n.Children)
                .Add(p => p.HasChildrenSelector, n => n.Children.Count > 0)
                .Add(p => p.KeySelector, n => n.Key)
                .Add(p => p.NodeContent, node => builder =>
                {
                    builder.AddMarkupContent(0, $"<span class=\"node-label\">{node.Label}</span>");
                });
        });
    }

    // ── Test 1: TreeView chevron toggle a11y attributes ────────────────────────

    [Fact]
    public void TreeViewToggle_HasAccessibleNameAndRole()
    {
        // BranchRoots has one branch node ("root-1") and one leaf node ("leaf-1").
        // The branch node's toggle span is the only .tv-toggle rendered.
        var cut = RenderTreeView();

        var toggle = cut.Find(".tv-toggle");

        // role="button" makes it announced as a button by screen readers.
        Assert.Equal("button", toggle.GetAttribute("role"));

        // tabindex="0" puts it in the natural tab order.
        Assert.Equal("0", toggle.GetAttribute("tabindex"));

        // aria-label must be non-empty (e.g. "Expand root-1").
        var label = toggle.GetAttribute("aria-label");
        Assert.NotNull(label);
        Assert.NotEmpty(label!);

        // aria-expanded reflects the collapsed state ("false" when collapsed).
        Assert.Equal("false", toggle.GetAttribute("aria-expanded"));
    }

    [Fact]
    public void TreeViewToggle_AriaExpanded_ReflectsExpandedState()
    {
        var cut = RenderTreeView();

        // Collapsed initially.
        var toggle = cut.Find(".tv-toggle");
        Assert.Equal("false", toggle.GetAttribute("aria-expanded"));

        // Click to expand.
        toggle.Click();

        // aria-expanded must now be "true".
        var expandedToggle = cut.Find(".tv-toggle");
        Assert.Equal("true", expandedToggle.GetAttribute("aria-expanded"));

        // aria-label should also flip to "Collapse …".
        var labelAfterExpand = expandedToggle.GetAttribute("aria-label");
        Assert.NotNull(labelAfterExpand);
        Assert.StartsWith("Collapse", labelAfterExpand!);
    }

    // ── Test 3: TreeView keyboard activation (Enter / Space) ──────────────────

    [Fact]
    public void TreeViewToggle_EnterKey_TogglesExpanded()
    {
        var cut = RenderTreeView();

        var toggle = cut.Find(".tv-toggle");
        Assert.Equal("false", toggle.GetAttribute("aria-expanded"));

        // Fire Enter on the toggle — should expand the branch.
        toggle.TriggerEvent("onkeydown", new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Key = "Enter" });

        var expandedToggle = cut.Find(".tv-toggle");
        Assert.Equal("true", expandedToggle.GetAttribute("aria-expanded"));
    }

    [Fact]
    public void TreeViewToggle_SpaceKey_TogglesExpanded()
    {
        var cut = RenderTreeView();

        var toggle = cut.Find(".tv-toggle");
        Assert.Equal("false", toggle.GetAttribute("aria-expanded"));

        // Fire Space on the toggle — should expand the branch.
        toggle.TriggerEvent("onkeydown", new Microsoft.AspNetCore.Components.Web.KeyboardEventArgs { Key = " " });

        var expandedToggle = cut.Find(".tv-toggle");
        Assert.Equal("true", expandedToggle.GetAttribute("aria-expanded"));
    }

    // ── Test 2: ToastNotification live-region regression lock ─────────────────

    [Fact]
    public void ToastNotification_Container_IsAriaLivePolite()
    {
        // Render ToastNotification — it has no required services/cascading params.
        var cut = Render<ToastNotification>();

        // The outermost div is the live-region container.
        // Find the element that carries aria-live (may be the root or a child div).
        var liveRegion = cut.Find("[aria-live]");

        Assert.Equal("polite", liveRegion.GetAttribute("aria-live"));
        Assert.Equal("true", liveRegion.GetAttribute("aria-atomic"));
    }
}
