using Microsoft.Playwright;

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

/// <summary>
/// Verifies that navigation sections and links are shown/hidden based on the user's role.
///
/// LDAP test users (all passwords: "password"):
///   admin       → Admin only
///   designer    → Design only
///   deployer    → Deployment only
///   multi-role  → Admin + Design + Deployment
///
/// Nav structure (from NavMenu.razor):
///   All authenticated: Dashboard, Health Dashboard
///   Admin:      LDAP Mappings, Sites, API Keys, SMTP Configuration, Audit Log
///   Design:     Templates, Shared Scripts, Connections, External Systems
///   Deployment: Topology, Deployments, Debug View, Event Logs, Parked Messages
/// </summary>
[Collection("Playwright")]
public class RoleNavigationTests
{
    private readonly PlaywrightFixture _fixture;

    public RoleNavigationTests(PlaywrightFixture fixture)
    {
        _fixture = fixture;
    }

    // ── Admin-only user ─────────────────────────────────────────────

    [Fact]
    public async Task AdminUser_SeesAdminSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("admin", "password");

        await AssertNavLinkVisible(page, "LDAP Mappings");
        await AssertNavLinkVisible(page, "Sites");
        await AssertNavLinkVisible(page, "API Keys");
        await AssertNavLinkVisible(page, "SMTP Configuration");
        await AssertNavLinkVisible(page, "Audit Log");
    }

    [Fact]
    public async Task AdminUser_DoesNotSeeDesignSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("admin", "password");

        await AssertNavLinkHidden(page, "Templates");
        await AssertNavLinkHidden(page, "Shared Scripts");
        await AssertNavLinkHidden(page, "Connections");
        await AssertNavLinkHidden(page, "External Systems");
    }

    [Fact]
    public async Task AdminUser_DoesNotSeeDeploymentSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("admin", "password");

        await AssertNavLinkHidden(page, "Topology");
        await AssertNavLinkHidden(page, "Deployments");
        await AssertNavLinkHidden(page, "Debug View");
    }

    [Fact]
    public async Task AdminUser_SeesHealthDashboard_NotDeploymentMonitoring()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("admin", "password");

        // Health Dashboard is all-roles; Event Logs and Parked Messages are
        // Deployment-role only (NavMenu.razor / Component-CentralUI).
        await AssertNavLinkVisible(page, "Health Dashboard");
        await AssertNavLinkHidden(page, "Event Logs");
        await AssertNavLinkHidden(page, "Parked Messages");
    }

    // ── Design-only user ────────────────────────────────────────────

    [Fact]
    public async Task DesignUser_SeesDesignSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("designer", "password");

        await AssertNavLinkVisible(page, "Templates");
        await AssertNavLinkVisible(page, "Shared Scripts");
        await AssertNavLinkVisible(page, "Connections");
        await AssertNavLinkVisible(page, "External Systems");
    }

    [Fact]
    public async Task DesignUser_DoesNotSeeAdminSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("designer", "password");

        await AssertNavLinkHidden(page, "LDAP Mappings");
        await AssertNavLinkHidden(page, "Sites");
        await AssertNavLinkHidden(page, "API Keys");
        await AssertNavLinkHidden(page, "SMTP Configuration");
        await AssertNavLinkHidden(page, "Audit Log");
    }

    [Fact]
    public async Task DesignUser_DoesNotSeeDeploymentSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("designer", "password");

        await AssertNavLinkHidden(page, "Topology");
        await AssertNavLinkHidden(page, "Deployments");
        await AssertNavLinkHidden(page, "Debug View");
    }

    [Fact]
    public async Task DesignUser_SeesHealthDashboard_NotDeploymentMonitoringOrAudit()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("designer", "password");

        // A Design-only user sees the all-roles Health Dashboard but not the
        // Deployment-gated Event Logs / Parked Messages, nor the Admin Audit Log.
        await AssertNavLinkVisible(page, "Health Dashboard");
        await AssertNavLinkHidden(page, "Event Logs");
        await AssertNavLinkHidden(page, "Parked Messages");
        await AssertNavLinkHidden(page, "Audit Log");
    }

    // ── Deployment-only user ────────────────────────────────────────

    [Fact]
    public async Task DeploymentUser_SeesDeploymentSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("deployer", "password");

        await AssertNavLinkVisible(page, "Topology");
        await AssertNavLinkVisible(page, "Deployments");
        await AssertNavLinkVisible(page, "Debug View");
    }

    [Fact]
    public async Task DeploymentUser_DoesNotSeeAdminSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("deployer", "password");

        await AssertNavLinkHidden(page, "LDAP Mappings");
        await AssertNavLinkHidden(page, "Sites");
        await AssertNavLinkHidden(page, "API Keys");
        await AssertNavLinkHidden(page, "SMTP Configuration");
        await AssertNavLinkHidden(page, "Audit Log");
    }

    [Fact]
    public async Task DeploymentUser_DoesNotSeeDesignSection()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("deployer", "password");

        await AssertNavLinkHidden(page, "Templates");
        await AssertNavLinkHidden(page, "Shared Scripts");
        await AssertNavLinkHidden(page, "Connections");
        await AssertNavLinkHidden(page, "External Systems");
    }

    [Fact]
    public async Task DeploymentUser_SeesMonitoringButNotConfigurationAuditLog()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("deployer", "password");

        // Event Logs and Parked Messages are Deployment-role gated, so a
        // Deployment user sees them; Configuration Audit Log is Admin-only.
        await AssertNavLinkVisible(page, "Health Dashboard");
        await AssertNavLinkVisible(page, "Event Logs");
        await AssertNavLinkVisible(page, "Parked Messages");
        await AssertNavLinkHidden(page, "Configuration Audit Log");
    }

    // ── Multi-role user (Admin + Design + Deployment) ───────────────

    [Fact]
    public async Task MultiRoleUser_SeesAllSections()
    {
        var page = await _fixture.NewAuthenticatedPageAsync("multi-role", "password");

        // Admin
        await AssertNavLinkVisible(page, "LDAP Mappings");
        await AssertNavLinkVisible(page, "Sites");
        await AssertNavLinkVisible(page, "API Keys");
        await AssertNavLinkVisible(page, "SMTP Configuration");
        await AssertNavLinkVisible(page, "Audit Log");

        // Design
        await AssertNavLinkVisible(page, "Templates");
        await AssertNavLinkVisible(page, "Shared Scripts");
        await AssertNavLinkVisible(page, "Connections");
        await AssertNavLinkVisible(page, "External Systems");

        // Deployment
        await AssertNavLinkVisible(page, "Topology");
        await AssertNavLinkVisible(page, "Deployments");
        await AssertNavLinkVisible(page, "Debug View");

        // Monitoring
        await AssertNavLinkVisible(page, "Health Dashboard");
        await AssertNavLinkVisible(page, "Event Logs");
        await AssertNavLinkVisible(page, "Parked Messages");
    }

    // ── All users see Dashboard ─────────────────────────────────────

    [Theory]
    [InlineData("admin")]
    [InlineData("designer")]
    [InlineData("deployer")]
    [InlineData("multi-role")]
    public async Task AllUsers_SeeDashboardLink(string username)
    {
        var page = await _fixture.NewAuthenticatedPageAsync(username, "password");

        var dashboardLink = page.GetByRole(AriaRole.Link, new() { Name = "Dashboard", Exact = true });
        await Assertions.Expect(dashboardLink).ToBeVisibleAsync();
    }

    // ── Helpers ─────────────────────────────────────────────────────

    private static async Task AssertNavLinkVisible(IPage page, string linkText)
    {
        // Sections are collapsed by default — expand them so a present link is
        // in the DOM. Idempotent: already-expanded sections are skipped.
        await PlaywrightFixture.ExpandAllNavSectionsAsync(page);
        var locator = page.Locator($"nav a:has-text('{linkText}')");
        var count = await locator.CountAsync();
        Assert.True(count > 0, $"Expected nav link '{linkText}' to be visible, but it was not found");
    }

    private static async Task AssertNavLinkHidden(IPage page, string linkText)
    {
        var locator = page.Locator($"nav a:has-text('{linkText}')");
        var count = await locator.CountAsync();
        Assert.True(count == 0, $"Expected nav link '{linkText}' to be hidden, but it was found");
    }
}
