using System.Text.Json;
using Tiku.Application.Security;

namespace Tiku.UnitTests.Security;

public sealed class CurrentDataScopeTests
{
    [Fact]
    public void Merge_EmptyOrInvalidScopes_DefaultsToSelf()
    {
        var result = CurrentDataScope.Merge(
        [
            JsonSerializer.SerializeToElement(new { }),
            JsonSerializer.SerializeToElement("invalid")
        ]);

        Assert.Equal(DataScopeMode.Self, result.Mode);
        Assert.True(result.IncludesSelf);
        Assert.Empty(result.RegionIds);
        Assert.Empty(result.ClassIds);
    }

    [Fact]
    public void Merge_RestrictedRoles_UnionsResourceIdsAndSelfAccess()
    {
        var firstRegion = Guid.NewGuid();
        var secondRegion = Guid.NewGuid();
        var classId = Guid.NewGuid();

        var result = CurrentDataScope.Merge(
        [
            JsonSerializer.SerializeToElement(new
            {
                mode = "Restricted",
                regionIds = new[] { firstRegion },
                classIds = new[] { classId }
            }),
            JsonSerializer.SerializeToElement(new
            {
                mode = "Restricted",
                regionIds = new[] { secondRegion },
                includesSelf = true
            })
        ]);

        Assert.Equal(DataScopeMode.Restricted, result.Mode);
        Assert.True(result.IncludesSelf);
        Assert.True(result.RegionIds.SetEquals([firstRegion, secondRegion]));
        Assert.True(result.ClassIds.SetEquals([classId]));
    }

    [Fact]
    public void Merge_AllScope_OverridesRestrictedScopes()
    {
        var result = CurrentDataScope.Merge(
        [
            JsonSerializer.SerializeToElement(new { mode = "Restricted", regionIds = new[] { Guid.NewGuid() } }),
            JsonSerializer.SerializeToElement(new { type = "All" })
        ]);

        Assert.Equal(DataScopeMode.All, result.Mode);
        Assert.True(result.IncludesSelf);
        Assert.Empty(result.RegionIds);
        Assert.Empty(result.ClassIds);
    }

    [Fact]
    public void PermissionCatalog_UsesUniqueRealmScopedCodes()
    {
        Assert.All(BackendPermissions.Tenant, code => Assert.StartsWith("tenant:", code, StringComparison.Ordinal));
        Assert.All(BackendPermissions.Platform, code => Assert.StartsWith("platform:", code, StringComparison.Ordinal));
        Assert.Empty(BackendPermissions.Tenant.Intersect(BackendPermissions.Platform, StringComparer.Ordinal));
    }

    [Fact]
    public void AllowsResource_UsesOwnerRegionAndClassWithoutCrossScopeFallback()
    {
        var userId = Guid.NewGuid();
        var regionId = Guid.NewGuid();
        var classId = Guid.NewGuid();
        var scope = new CurrentDataScope(
            DataScopeMode.Restricted,
            new HashSet<Guid> { regionId },
            new HashSet<Guid> { classId },
            false);

        Assert.True(scope.AllowsResource(userId, regionId: regionId));
        Assert.True(scope.AllowsResource(userId, classId: classId));
        Assert.False(scope.AllowsResource(userId, userId));
        Assert.False(scope.AllowsResource(userId, regionId: Guid.NewGuid(), classId: Guid.NewGuid()));
    }
}