using System.Net;
using System.Text.Json;
using Tiku.Application.Security;
using Tiku.Domain.Common;
using Tiku.Domain.Identity;
using Tiku.Domain.Operations;
using Tiku.Domain.Tenancy;

namespace Tiku.IntegrationTests.Api;

public sealed class BackofficeUiBootstrapTests
{
    [Fact]
    public async Task TenantUiBootstrap_ReturnsOnlyMenusAllowedByEffectivePermissions()
    {
        var commandRecorder = new RecordingDbCommandInterceptor();
        await using var factory = new ApiTestFactory(dbCommandInterceptor: commandRecorder);
        await factory.SeedBuiltinBackofficeCatalogAsync();
        var tenantId = Guid.NewGuid();
        var userId = Guid.NewGuid();
        var roleId = Guid.NewGuid();
        var phone = "13710000000";
        await factory.SeedAsync(
            new Tenant
            {
                Id = tenantId,
                Slug = tenantId.ToString("N"),
                Name = "Scoped UI Tenant",
                Status = TenantStatus.Active,
                Metadata = JsonDefaults.Object()
            },
            new User
            {
                Id = userId,
                Phone = phone,
                Name = "Dashboard Operator"
            }.WithTestPassword(),
            new TenantMembership
            {
                TenantId = tenantId,
                UserId = userId,
                Role = TenantRole.Student,
                Status = MembershipStatus.Active
            },
            new TenantBackendRole
            {
                Id = roleId,
                TenantId = tenantId,
                Code = "dashboard_operator",
                Name = "Dashboard Operator",
                Status = BackendRoleStatus.Active,
                DataScope = JsonSerializer.SerializeToElement(new { mode = "self" })
            },
            new TenantBackendRolePermission
            {
                TenantId = tenantId,
                RoleId = roleId,
                PermissionCode = BackendPermissions.TenantDashboardView
            },
            new TenantBackendUserRole
            {
                TenantId = tenantId,
                UserId = userId,
                RoleId = roleId
            });

        using var client = factory.CreateClient();
        client.UseAccessToken(await client.LoginAsTenantAsync(tenantId, phone));

        commandRecorder.Reset();
        using var response = await client.GetAsync("/api/tenant/access/ui-bootstrap");
        using var bootstrap = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
        var firstRequestCommands = commandRecorder.Snapshot();
        commandRecorder.Reset();
        using var repeatedResponse = await client.GetAsync("/api/tenant/access/ui-bootstrap");
        var repeatedRequestCommands = commandRecorder.Snapshot();
        using var roleManagementResponse = await client.GetAsync("/api/tenant/access/bootstrap");

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(HttpStatusCode.OK, repeatedResponse.StatusCode);
        Assert.Equal(
            [BackendPermissions.TenantDashboardView],
            bootstrap.RootElement.GetProperty("permissionCodes").EnumerateArray().Select(item => item.GetString()));
        Assert.Equal(
            ["tenant.dashboard"],
            bootstrap.RootElement.GetProperty("menus").EnumerateArray()
                .Select(item => item.GetProperty("code").GetString()));
        Assert.True(
            firstRequestCommands.Count is >= 1 and <= 10,
            $"Expected at most 10 SQL commands, but captured {firstRequestCommands.Count}:{Environment.NewLine}{string.Join($"{Environment.NewLine}---{Environment.NewLine}", firstRequestCommands)}");
        Assert.InRange(repeatedRequestCommands.Count, 1, firstRequestCommands.Count);
        AssertNoPerCodeCatalogExistenceQueries(firstRequestCommands);
        AssertNoPerCodeCatalogExistenceQueries(repeatedRequestCommands);
        Assert.Equal(HttpStatusCode.Forbidden, roleManagementResponse.StatusCode);
    }

    [Fact]
    public async Task PlatformUiBootstrap_DoesNotProbeCatalogPerCode()
    {
        var commandRecorder = new RecordingDbCommandInterceptor();
        await using var factory = new ApiTestFactory(
            configurationOverrides: new Dictionary<string, string?>
            {
                ["Tenancy:Resolution:PlatformHosts:0"] = "localhost"
            },
            dbCommandInterceptor: commandRecorder);
        await factory.SeedBuiltinBackofficeCatalogAsync();
        var userId = Guid.NewGuid();
        var roleId = Guid.NewGuid();
        var email = $"platform-{Guid.NewGuid():N}@example.test";
        await factory.SeedAsync(
            new User
            {
                Id = userId,
                Email = email,
                NormalizedEmail = email.ToUpperInvariant(),
                UserName = email,
                NormalizedUserName = email.ToUpperInvariant(),
                Name = "Platform UI Operator",
                PrimaryRole = "platform_admin",
                RawProfile = JsonDefaults.Object()
            }.WithTestPassword(),
            new PlatformBackendRole
            {
                Id = roleId,
                Code = $"platform_ui_{Guid.NewGuid():N}",
                Name = "Platform UI Operator",
                Status = BackendRoleStatus.Active
            },
            new PlatformBackendRolePermission
            {
                RoleId = roleId,
                PermissionCode = BackendPermissions.PlatformDashboardView
            },
            new PlatformBackendUserRole
            {
                UserId = userId,
                RoleId = roleId
            });

        using var client = factory.CreateClient();
        client.UseAccessToken(await client.LoginAsPlatformAsync(email));

        commandRecorder.Reset();
        using var response = await client.GetAsync("/api/platform/access/ui-bootstrap");
        using var bootstrap = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
        var commands = commandRecorder.Snapshot();

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal(
            [BackendPermissions.PlatformDashboardView],
            bootstrap.RootElement.GetProperty("permissionCodes").EnumerateArray().Select(item => item.GetString()));
        Assert.Equal(
            ["platform.dashboard"],
            bootstrap.RootElement.GetProperty("menus").EnumerateArray()
                .Select(item => item.GetProperty("code").GetString()));
        Assert.InRange(commands.Count, 1, 10);
        AssertNoPerCodeCatalogExistenceQueries(commands);
    }

    private static void AssertNoPerCodeCatalogExistenceQueries(IEnumerable<string> commands)
    {
        string[] catalogTables = ["saas_features", "permission_modules", "backend_permissions", "backend_menus"];
        Assert.DoesNotContain(commands, command =>
            command.TrimStart().StartsWith("SELECT EXISTS", StringComparison.OrdinalIgnoreCase) &&
            catalogTables.Any(table => command.Contains(table, StringComparison.OrdinalIgnoreCase)));
    }
}