using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
using ZB.MOM.WW.OtOpcUa.Security.Ldap;

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

public sealed class RoleMapperTests
{
    /// <summary>
    /// Verifies that empty mapping returns no roles.
    /// </summary>
    [Fact]
    public void Empty_mapping_returns_empty()
    {
        RoleMapper.Map(new[] { "Admins" }, new Dictionary<string, string>())
            .ShouldBeEmpty();
    }

    /// <summary>
    /// Verifies that RoleMapper maps a group to its corresponding role.
    /// </summary>
    [Fact]
    public void Maps_group_to_role()
    {
        RoleMapper.Map(
            new[] { "AdminGroup" },
            new Dictionary<string, string> { ["AdminGroup"] = "Administrator" })
            .ShouldBe(new[] { "Administrator" });
    }

    /// <summary>
    /// Verifies that group matching is case-insensitive.
    /// </summary>
    [Fact]
    public void Case_insensitive_group_match()
    {
        RoleMapper.Map(
            new[] { "admingroup" },
            new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
            {
                ["AdminGroup"] = "Administrator",
            })
            .ShouldBe(new[] { "Administrator" });
    }

    /// <summary>
    /// Verifies that multiple groups are deduplicated to unique roles.
    /// </summary>
    [Fact]
    public void Multiple_groups_dedup_roles()
    {
        var roles = RoleMapper.Map(
            new[] { "AdminGroup", "AlsoAdmin" },
            new Dictionary<string, string>
            {
                ["AdminGroup"] = "Administrator",
                ["AlsoAdmin"] = "Administrator",
            });

        roles.ShouldBe(new[] { "Administrator" });
    }

    [Fact]
    public void Merge_unions_baseline_and_systemwide_db_roles()
    {
        var rows = new[]
        {
            new LdapGroupRoleMapping { LdapGroup = "g1", Role = AdminRole.Administrator, IsSystemWide = true },
            new LdapGroupRoleMapping { LdapGroup = "g2", Role = AdminRole.Designer, IsSystemWide = false, ClusterId = "SITE-A" },
        };
        var result = RoleMapper.Merge(["Viewer"], rows);
        result.ShouldContain("Viewer");
        result.ShouldContain("Administrator");
        result.ShouldNotContain("Designer");   // cluster-scoped row ignored (global-only)
    }

    [Fact]
    public void Merge_with_no_db_rows_returns_baseline()
        => RoleMapper.Merge(["Administrator"], []).ShouldBe(["Administrator"]);
}
