using Microsoft.EntityFrameworkCore;
using Tiku.Application.Security;
using Tiku.Domain.Operations;
using Tiku.Domain.Platform;
using Tiku.Infrastructure.Bootstrap;
using Tiku.Infrastructure.Persistence;
using Tiku.IntegrationTests.Infrastructure;

namespace Tiku.IntegrationTests.Bootstrap;

public sealed class BuiltinBackofficeCatalogSeederTests
{
    [Fact]
    public async Task Seed_populates_complete_catalog_and_is_idempotent()
    {
        using var database = PostgresTestDatabase.Create();
        await using var dbContext = CreateDbContext(database.ConnectionString);
        var seeder = new BuiltinBackofficeCatalogSeeder(dbContext);

        await seeder.SeedAsync();
        dbContext.ChangeTracker.Clear();
        await seeder.SeedAsync();

        Assert.Equal(15, await dbContext.SaasFeatures.CountAsync());
        Assert.Equal(28, await dbContext.PermissionModules.CountAsync());
        Assert.Equal(42, await dbContext.BackendPermissions.CountAsync());
        Assert.Equal(29, await dbContext.BackendMenus.CountAsync());
        Assert.Equal(15, await dbContext.SaasFeatures.Select(item => item.Code).Distinct().CountAsync());
        Assert.Equal(28, await dbContext.PermissionModules.Select(item => item.Code).Distinct().CountAsync());
        Assert.Equal(42, await dbContext.BackendPermissions.Select(item => item.Code).Distinct().CountAsync());
        Assert.Equal(29, await dbContext.BackendMenus.Select(item => item.Code).Distinct().CountAsync());
        Assert.True(await dbContext.PermissionModules.AnyAsync(item => item.Code == "platform_operations"));
        Assert.True(await dbContext.BackendPermissions.AnyAsync(item =>
            item.Code == BackendPermissions.PlatformOperationsView &&
            item.PermissionModuleCode == "platform_operations"));
        Assert.True(await dbContext.BackendPermissions.AnyAsync(item =>
            item.Code == BackendPermissions.PlatformOperationsManage &&
            item.PermissionModuleCode == "platform_operations"));
    }

    [Fact]
    public async Task Seed_preserves_existing_values_and_fills_partial_catalog()
    {
        using var database = PostgresTestDatabase.Create();
        await using var dbContext = CreateDbContext(database.ConnectionString);
        dbContext.SaasFeatures.Add(new SaasFeature
        {
            Code = SaasFeatureCatalog.CoreBackoffice,
            Name = "Custom feature name",
            Category = "custom",
            IsCore = true,
            Status = SaasFeatureStatus.Active
        });
        dbContext.PermissionModules.Add(new PermissionModule
        {
            Code = "tenant_dashboard",
            Name = "Custom module name",
            Area = BackendPermissionArea.Tenant
        });
        dbContext.BackendPermissions.Add(new BackendPermission
        {
            Code = BackendPermissions.TenantDashboardView,
            Name = "Custom permission name",
            Area = BackendPermissionArea.Tenant,
            PermissionModuleCode = "tenant_dashboard",
            IsSystem = true
        });
        dbContext.BackendMenus.Add(new BackendMenu
        {
            Code = "tenant.dashboard",
            Title = "Custom menu title",
            Area = BackendPermissionArea.Tenant,
            Path = "/custom-dashboard",
            PermissionCode = BackendPermissions.TenantDashboardView,
            IsActive = true
        });
        await dbContext.SaveChangesAsync();
        dbContext.ChangeTracker.Clear();

        await new BuiltinBackofficeCatalogSeeder(dbContext).SeedAsync();

        Assert.Equal("Custom feature name",
            (await dbContext.SaasFeatures.SingleAsync(item => item.Code == SaasFeatureCatalog.CoreBackoffice)).Name);
        Assert.Equal("Custom module name",
            (await dbContext.PermissionModules.SingleAsync(item => item.Code == "tenant_dashboard")).Name);
        Assert.Equal("Custom permission name",
            (await dbContext.BackendPermissions.SingleAsync(item =>
                item.Code == BackendPermissions.TenantDashboardView)).Name);
        Assert.Equal("Custom menu title",
            (await dbContext.BackendMenus.SingleAsync(item => item.Code == "tenant.dashboard")).Title);
        Assert.Equal(15, await dbContext.SaasFeatures.CountAsync());
        Assert.Equal(28, await dbContext.PermissionModules.CountAsync());
        Assert.Equal(42, await dbContext.BackendPermissions.CountAsync());
        Assert.Equal(29, await dbContext.BackendMenus.CountAsync());
        Assert.False(await dbContext.PermissionModules.AnyAsync(module =>
            module.RequiredFeatureCode != null &&
            !dbContext.SaasFeatures.Any(feature => feature.Code == module.RequiredFeatureCode)));
        Assert.False(await dbContext.BackendPermissions.AnyAsync(permission =>
            !dbContext.PermissionModules.Any(module => module.Code == permission.PermissionModuleCode)));
        Assert.False(await dbContext.BackendMenus.AnyAsync(menu =>
            menu.PermissionCode != null &&
            !dbContext.BackendPermissions.Any(permission => permission.Code == menu.PermissionCode)));
    }

    [Fact]
    public async Task Seed_backfills_new_permissions_for_existing_system_super_admin()
    {
        using var database = PostgresTestDatabase.Create();
        await using var dbContext = CreateDbContext(database.ConnectionString);
        var seeder = new BuiltinBackofficeCatalogSeeder(dbContext);
        await seeder.SeedAsync();
        var role = new PlatformBackendRole
        {
            Code = PlatformAdminBootstrapper.SuperAdminRoleCode,
            Name = "超级管理员",
            Status = BackendRoleStatus.Active,
            IsSystem = true
        };
        dbContext.PlatformBackendRoles.Add(role);
        dbContext.PlatformBackendRolePermissions.Add(new PlatformBackendRolePermission
        {
            RoleId = role.Id,
            PermissionCode = BackendPermissions.PlatformDashboardView
        });
        await dbContext.SaveChangesAsync();
        dbContext.ChangeTracker.Clear();

        await seeder.SeedAsync();
        dbContext.ChangeTracker.Clear();
        await seeder.SeedAsync();

        var permissionCodes = await dbContext.PlatformBackendRolePermissions.AsNoTracking()
            .Where(binding => binding.RoleId == role.Id)
            .Select(binding => binding.PermissionCode)
            .ToArrayAsync();
        Assert.Equal(BackendPermissions.Platform.Count, permissionCodes.Length);
        Assert.Contains(BackendPermissions.PlatformQuestionBankManage, permissionCodes);
        Assert.Equal(BackendPermissions.Platform.Count, permissionCodes.Distinct(StringComparer.Ordinal).Count());
    }

    private static TikuDbContext CreateDbContext(string connectionString)
    {
        var options = new DbContextOptionsBuilder<TikuDbContext>()
            .UseNpgsql(connectionString, npgsql =>
                npgsql.MigrationsAssembly(typeof(TikuDbContext).Assembly.FullName))
            .Options;
        return new TikuDbContext(options);
    }
}