using SharepointToolbox.Core.Helpers;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Tests.Helpers;

/// <summary>
/// Unit tests for PermissionConsolidator static helper.
/// RPT-04: Validates consolidation logic for empty input, single entry, merging,
/// case-insensitivity, MakeKey format, the 10-row/7-row scenario, LocationCount,
/// and preservation of IsHighPrivilege / IsExternalUser flags.
/// </summary>
public class PermissionConsolidatorTests
{
    // ---------------------------------------------------------------------------
    // Helper factory — reduces boilerplate across all test methods
    // ---------------------------------------------------------------------------

    private static UserAccessEntry MakeEntry(
        string userLogin = "alice@contoso.com",
        string siteUrl = "https://contoso.sharepoint.com/sites/hr",
        string siteTitle = "HR Site",
        string objectType = "List",
        string objectTitle = "Documents",
        string objectUrl = "https://contoso.sharepoint.com/sites/hr/Documents",
        string permissionLevel = "Contribute",
        AccessType accessType = AccessType.Direct,
        string grantedThrough = "Direct Permissions",
        string userDisplayName = "Alice Smith",
        bool isHighPrivilege = false,
        bool isExternalUser = false)
    {
        return new UserAccessEntry(
            userDisplayName, userLogin, siteUrl, siteTitle,
            objectType, objectTitle, objectUrl,
            permissionLevel, accessType, grantedThrough,
            isHighPrivilege, isExternalUser);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-a: Empty input returns empty list
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_EmptyInput_ReturnsEmptyList()
    {
        var result = PermissionConsolidator.Consolidate(Array.Empty<UserAccessEntry>());

        Assert.Empty(result);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-b: Single entry produces 1 consolidated row with 1 location
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_SingleEntry_ReturnsOneRowWithOneLocation()
    {
        var entry = MakeEntry();

        var result = PermissionConsolidator.Consolidate(new[] { entry });

        var row = Assert.Single(result);
        Assert.Single(row.Locations);
        Assert.Equal("alice@contoso.com", row.UserLogin);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-c: 3 entries with same key (different sites) merge to 1 row with 3 locations
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_ThreeEntriesSameKey_ReturnsOneRowWithThreeLocations()
    {
        var entries = new[]
        {
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/hr",   siteTitle: "HR Site"),
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/fin",  siteTitle: "Finance Site"),
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/mkt",  siteTitle: "Marketing Site"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        Assert.Single(result);
        Assert.Equal(3, result[0].Locations.Count);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-d: Entries with different keys remain as separate rows
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_DifferentKeys_RemainSeparateRows()
    {
        var entries = new[]
        {
            MakeEntry(permissionLevel: "Contribute"),
            MakeEntry(permissionLevel: "Full Control"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        Assert.Equal(2, result.Count);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-e: Case-insensitive key — "ALICE@CONTOSO.COM" and "alice@contoso.com" merge
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_CaseInsensitiveKey_MergesCorrectly()
    {
        var entries = new[]
        {
            MakeEntry(userLogin: "ALICE@CONTOSO.COM", siteUrl: "https://contoso.sharepoint.com/sites/hr"),
            MakeEntry(userLogin: "alice@contoso.com",  siteUrl: "https://contoso.sharepoint.com/sites/fin"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        Assert.Single(result);
        Assert.Equal(2, result[0].Locations.Count);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-f: MakeKey produces pipe-delimited lowercase format
    // ---------------------------------------------------------------------------

    [Fact]
    public void MakeKey_ProducesPipeDelimitedLowercaseFormat()
    {
        var entry = MakeEntry(
            userLogin: "Alice@Contoso.com",
            permissionLevel: "Full Control",
            accessType: AccessType.Direct,
            grantedThrough: "Direct Permissions");

        var key = PermissionConsolidator.MakeKey(entry);

        // AccessType.ToString() preserves casing ("Direct"); all string fields are lowercased
        Assert.Equal("alice@contoso.com|full control|Direct|direct permissions", key);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-g: 10-row input with 3 duplicate pairs produces 7 consolidated rows
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_TenRowsWithThreeDuplicatePairs_ReturnsSevenRows()
    {
        var entries = new[]
        {
            // alice / Contribute / Direct — 3 entries -> merges to 1
            MakeEntry(userLogin: "alice@contoso.com", permissionLevel: "Contribute",
                      accessType: AccessType.Direct, grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr",  siteTitle: "HR"),
            MakeEntry(userLogin: "alice@contoso.com", permissionLevel: "Contribute",
                      accessType: AccessType.Direct, grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/fin", siteTitle: "Finance"),
            MakeEntry(userLogin: "alice@contoso.com", permissionLevel: "Contribute",
                      accessType: AccessType.Direct, grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/mkt", siteTitle: "Marketing"),

            // bob / Full Control / Group — 2 entries -> merges to 1
            MakeEntry(userLogin: "bob@contoso.com", userDisplayName: "Bob Jones",
                      permissionLevel: "Full Control", accessType: AccessType.Group,
                      grantedThrough: "SharePoint Group: Owners",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr",  siteTitle: "HR"),
            MakeEntry(userLogin: "bob@contoso.com", userDisplayName: "Bob Jones",
                      permissionLevel: "Full Control", accessType: AccessType.Group,
                      grantedThrough: "SharePoint Group: Owners",
                      siteUrl: "https://contoso.sharepoint.com/sites/fin", siteTitle: "Finance"),

            // carol / Read / Inherited — 2 entries -> merges to 1
            MakeEntry(userLogin: "carol@contoso.com", userDisplayName: "Carol White",
                      permissionLevel: "Read", accessType: AccessType.Inherited,
                      grantedThrough: "Inherited Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr",  siteTitle: "HR"),
            MakeEntry(userLogin: "carol@contoso.com", userDisplayName: "Carol White",
                      permissionLevel: "Read", accessType: AccessType.Inherited,
                      grantedThrough: "Inherited Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/fin", siteTitle: "Finance"),

            // alice / Full Control / Direct — different key from alice's Contribute -> unique row
            MakeEntry(userLogin: "alice@contoso.com", permissionLevel: "Full Control",
                      accessType: AccessType.Direct, grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr", siteTitle: "HR"),

            // dave — unique
            MakeEntry(userLogin: "dave@contoso.com", userDisplayName: "Dave Brown",
                      permissionLevel: "Contribute", accessType: AccessType.Direct,
                      grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr", siteTitle: "HR"),

            // eve — unique
            MakeEntry(userLogin: "eve@contoso.com", userDisplayName: "Eve Green",
                      permissionLevel: "Read", accessType: AccessType.Direct,
                      grantedThrough: "Direct Permissions",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr", siteTitle: "HR"),

            // frank — unique (4th unique row)
            MakeEntry(userLogin: "frank@contoso.com", userDisplayName: "Frank Black",
                      permissionLevel: "Contribute", accessType: AccessType.Group,
                      grantedThrough: "SharePoint Group: Members",
                      siteUrl: "https://contoso.sharepoint.com/sites/hr", siteTitle: "HR"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        // 3 merged groups (alice-Contribute 3->1, bob 2->1, carol 2->1) + 4 unique rows
        // (alice-FullControl, dave, eve, frank) = 7 total
        Assert.Equal(7, result.Count);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-h: LocationCount property equals Locations.Count for a merged entry
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_MergedEntry_LocationCountMatchesLocationsCount()
    {
        var entries = new[]
        {
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/hr",  siteTitle: "HR"),
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/fin", siteTitle: "Finance"),
            MakeEntry(siteUrl: "https://contoso.sharepoint.com/sites/mkt", siteTitle: "Marketing"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        Assert.Single(result);
        Assert.Equal(result[0].Locations.Count, result[0].LocationCount);
        Assert.Equal(3, result[0].LocationCount);
    }

    // ---------------------------------------------------------------------------
    // RPT-04-i: IsHighPrivilege and IsExternalUser from first entry are preserved
    // ---------------------------------------------------------------------------

    [Fact]
    public void Consolidate_PreservesIsHighPrivilegeAndIsExternalUser()
    {
        var entries = new[]
        {
            MakeEntry(isHighPrivilege: true, isExternalUser: true,
                      siteUrl: "https://contoso.sharepoint.com/sites/hr"),
            MakeEntry(isHighPrivilege: false, isExternalUser: false,
                      siteUrl: "https://contoso.sharepoint.com/sites/fin"),
        };

        var result = PermissionConsolidator.Consolidate(entries);

        Assert.Single(result);
        Assert.True(result[0].IsHighPrivilege);
        Assert.True(result[0].IsExternalUser);
    }
}
