using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Identity;
using Tiku.Domain.Tenancy;

namespace Tiku.Infrastructure.Persistence.Configurations;

internal sealed class TenantConfiguration : IEntityTypeConfiguration<Tenant>
{
    public void Configure(EntityTypeBuilder<Tenant> builder)
    {
        builder.ConfigureEntity("tenants");
        builder.ConfigureTimestamps();

        builder.Property(entity => entity.Slug).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Name).HasMaxLength(200);
        builder.Property(entity => entity.LegalName).HasMaxLength(300);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Mode).HasSnakeCaseEnum();
        builder.Property(entity => entity.BillingStatus).HasSnakeCaseEnum();
        builder.Property(entity => entity.LegacyId).HasMaxLength(64);
        builder.Property(entity => entity.Metadata).IsJson("{}");

        builder.HasIndex(entity => entity.Slug).IsUnique();
        builder.HasIndex(entity => entity.LegacyId).IsUnique();
        builder.HasIndex(entity => entity.Mode)
            .IsUnique()
            .HasFilter("mode = 'platform_owned'");

        builder.HasOne<User>()
            .WithMany()
            .HasForeignKey(entity => entity.OwnerUserId)
            .OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class TenantMembershipConfiguration : IEntityTypeConfiguration<TenantMembership>
{
    public void Configure(EntityTypeBuilder<TenantMembership> builder)
    {
        builder.ConfigureTenantEntity("tenant_memberships");
        builder.ConfigureTimestamps();

        builder.Property(entity => entity.Role).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.LegacyRole).HasMaxLength(50);

        builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.Role }).IsUnique();

        builder.HasOne<User>()
            .WithMany()
            .HasForeignKey(entity => entity.UserId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class TenantDomainConfiguration : IEntityTypeConfiguration<TenantDomain>
{
    public void Configure(EntityTypeBuilder<TenantDomain> builder)
    {
        builder.ConfigureTenantEntity("tenant_domains");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.Host).HasColumnType("citext").HasMaxLength(253);
        builder.Property(entity => entity.DomainType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.VerificationToken).HasMaxLength(256);
        builder.Property(entity => entity.LastFailureReason).HasMaxLength(2000);
        builder.HasIndex(entity => entity.Host)
            .IsUnique()
            .HasAnnotation("Tiku:GlobalUnique", true);
        builder.HasIndex(entity => new { entity.TenantId, entity.IsPrimary })
            .IsUnique()
            .HasFilter("is_primary");
    }
}

internal sealed class TenantBrandingConfiguration : IEntityTypeConfiguration<TenantBranding>
{
    public void Configure(EntityTypeBuilder<TenantBranding> builder)
    {
        builder.ToTable("tenant_branding");
        builder.HasKey(entity => entity.TenantId);
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.BrandName).HasMaxLength(200);
        builder.Property(entity => entity.ShortName).HasMaxLength(100);
        builder.Property(entity => entity.Slogan).HasMaxLength(300);
        builder.Property(entity => entity.OrganizationName).HasMaxLength(300);
        builder.Property(entity => entity.LogoUrl).HasMaxLength(2048);
        builder.Property(entity => entity.FaviconUrl).HasMaxLength(2048);
        builder.Property(entity => entity.ServiceWechat).HasMaxLength(100);
        builder.Property(entity => entity.ServiceAccountName).HasMaxLength(200);
        builder.Property(entity => entity.Theme).IsJson("{}");
        builder.Property(entity => entity.PublicAssets).IsJson("{}");

        builder.HasOne<Tenant>().WithOne()
            .HasForeignKey<TenantBranding>(entity => entity.TenantId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class TenantSettingsConfiguration : IEntityTypeConfiguration<TenantSettings>
{
    public void Configure(EntityTypeBuilder<TenantSettings> builder)
    {
        builder.ToTable("tenant_settings");
        builder.HasKey(entity => entity.TenantId);
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.FeatureFlags).IsJson("{}");
        builder.Property(entity => entity.AdminFeatureFlags).IsJson("{}");
        builder.Property(entity => entity.PublicConfig).IsJson("{}");

        builder.HasOne<Tenant>().WithOne()
            .HasForeignKey<TenantSettings>(entity => entity.TenantId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class TenantAuthPolicyConfiguration : IEntityTypeConfiguration<TenantAuthPolicy>
{
    public void Configure(EntityTypeBuilder<TenantAuthPolicy> builder)
    {
        builder.ToTable("tenant_auth_policies");
        builder.HasKey(entity => entity.TenantId);
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.AllowExternalStudentSelfRegistration).HasDefaultValue(false);
        builder.Property(entity => entity.AllowedStudentLoginMethods)
            .HasColumnType("text[]")
            .HasDefaultValueSql("ARRAY['password']::text[]");
        builder.HasOne<Tenant>().WithOne()
            .HasForeignKey<TenantAuthPolicy>(entity => entity.TenantId)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class TenantFrontendConfigConfiguration : IEntityTypeConfiguration<TenantFrontendConfig>
{
    public void Configure(EntityTypeBuilder<TenantFrontendConfig> builder)
    {
        builder.ConfigureTenantEntity("tenant_frontend_configs");
        builder.ConfigureTimestamps();
        builder.HasIndex(entity => entity.TenantId).IsUnique();
        builder.Property(entity => entity.ConfigVersion).IsConcurrencyToken();
        builder.Property(entity => entity.PublishedBranding).IsJson("{}");
        builder.Property(entity => entity.PublishedTheme).IsJson("{}");
        builder.Property(entity => entity.PublishedFeatures).IsJson("{}");
        builder.Property(entity => entity.PublishedNavigation).IsJson("[]");
        builder.Property(entity => entity.PublishedHomeModules).IsJson("[]");
        builder.Property(entity => entity.DraftBranding).IsJson("{}");
        builder.Property(entity => entity.DraftTheme).IsJson("{}");
        builder.Property(entity => entity.DraftFeatures).IsJson("{}");
        builder.Property(entity => entity.DraftNavigation).IsJson("[]");
        builder.Property(entity => entity.DraftHomeModules).IsJson("[]");
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_tenant_frontend_configs_schema_version", "schema_version > 0");
            table.HasCheckConstraint("ck_tenant_frontend_configs_config_version", "config_version > 0");
        });
    }
}