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

namespace Tiku.Infrastructure.Persistence.Configurations;

internal sealed class SaasFeatureConfiguration : IEntityTypeConfiguration<SaasFeature>
{
    public void Configure(EntityTypeBuilder<SaasFeature> builder)
    {
        builder.ConfigureEntity("saas_features");
        builder.ConfigureTimestamps();
        builder.Property(value => value.Code).HasMaxLength(120);
        builder.Property(value => value.Name).HasMaxLength(200);
        builder.Property(value => value.Category).HasMaxLength(100);
        builder.Property(value => value.Description).HasMaxLength(1000);
        builder.Property(value => value.Currency).HasMaxLength(10);
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.HasIndex(value => value.Code).IsUnique();
        builder.HasIndex(value => new { value.Status, value.Category, value.SortOrder });
        builder.ToTable(table => table.HasCheckConstraint("ck_saas_features_reference_price", "reference_price_cents >= 0"));
    }
}

internal sealed class PermissionModuleConfiguration : IEntityTypeConfiguration<PermissionModule>
{
    public void Configure(EntityTypeBuilder<PermissionModule> builder)
    {
        builder.ConfigureEntity("permission_modules");
        builder.ConfigureTimestamps();
        builder.Property(value => value.Code).HasMaxLength(120);
        builder.Property(value => value.Name).HasMaxLength(200);
        builder.Property(value => value.Area).HasSnakeCaseEnum();
        builder.Property(value => value.RequiredFeatureCode).HasMaxLength(120);
        builder.Property(value => value.Description).HasMaxLength(1000);
        builder.HasIndex(value => value.Code).IsUnique();
        builder.HasIndex(value => new { value.Area, value.SortOrder });
        builder.HasOne<SaasFeature>().WithMany()
            .HasPrincipalKey(value => value.Code)
            .HasForeignKey(value => value.RequiredFeatureCode)
            .OnDelete(DeleteBehavior.Restrict);
    }
}

internal sealed class SaasOfferingConfiguration : IEntityTypeConfiguration<SaasOffering>
{
    public void Configure(EntityTypeBuilder<SaasOffering> builder)
    {
        builder.ConfigureEntity("saas_offerings");
        builder.ConfigureTimestamps();
        builder.Property(value => value.Code).HasMaxLength(120);
        builder.Property(value => value.Name).HasMaxLength(200);
        builder.Property(value => value.Type).HasSnakeCaseEnum();
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.Description).HasMaxLength(1000);
        builder.HasIndex(value => value.Code).IsUnique();
        builder.HasIndex(value => new { value.Type, value.Status, value.SortOrder });
    }
}

internal sealed class SaasOfferingVersionConfiguration : IEntityTypeConfiguration<SaasOfferingVersion>
{
    public void Configure(EntityTypeBuilder<SaasOfferingVersion> builder)
    {
        builder.ConfigureEntity("saas_offering_versions");
        builder.ConfigureTimestamps();
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.BillingCycle).HasSnakeCaseEnum();
        builder.Property(value => value.Currency).HasMaxLength(10);
        builder.Property(value => value.Metadata).IsJson("{}");
        builder.HasIndex(value => new { value.OfferingId, value.Version }).IsUnique();
        builder.HasIndex(value => new { value.OfferingId, value.Status, value.EffectiveAt });
        builder.HasOne<SaasOffering>().WithMany().HasForeignKey(value => value.OfferingId).OnDelete(DeleteBehavior.Cascade);
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_saas_offering_versions_version", "version > 0");
            table.HasCheckConstraint("ck_saas_offering_versions_amount", "original_amount_cents >= 0 and amount_cents >= 0 and amount_cents <= original_amount_cents");
        });
    }
}

internal sealed class SaasOfferingVersionFeatureConfiguration : IEntityTypeConfiguration<SaasOfferingVersionFeature>
{
    public void Configure(EntityTypeBuilder<SaasOfferingVersionFeature> builder)
    {
        builder.ConfigureEntity("saas_offering_version_features");
        builder.Property(value => value.FeatureCode).HasMaxLength(120);
        builder.HasIndex(value => new { value.OfferingVersionId, value.FeatureCode }).IsUnique();
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.OfferingVersionId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<SaasFeature>().WithMany().HasPrincipalKey(value => value.Code).HasForeignKey(value => value.FeatureCode).OnDelete(DeleteBehavior.Restrict);
    }
}

internal sealed class SaasFeatureLimitDefinitionConfiguration : IEntityTypeConfiguration<SaasFeatureLimitDefinition>
{
    public void Configure(EntityTypeBuilder<SaasFeatureLimitDefinition> builder)
    {
        builder.ConfigureEntity("saas_feature_limit_definitions");
        builder.ConfigureTimestamps();
        builder.Property(value => value.MetricCode).HasMaxLength(120);
        builder.Property(value => value.FeatureCode).HasMaxLength(120);
        builder.Property(value => value.Name).HasMaxLength(200);
        builder.Property(value => value.Unit).HasMaxLength(50);
        builder.Property(value => value.Kind).HasSnakeCaseEnum();
        builder.HasIndex(value => value.MetricCode).IsUnique();
        builder.HasIndex(value => new { value.FeatureCode, value.Kind });
        builder.HasOne<SaasFeature>().WithMany().HasPrincipalKey(value => value.Code).HasForeignKey(value => value.FeatureCode).OnDelete(DeleteBehavior.Cascade);
        builder.ToTable(table => table.HasCheckConstraint("ck_saas_feature_limit_warning", "warning_percent between 1 and 100"));
    }
}

internal sealed class SaasOfferingVersionLimitConfiguration : IEntityTypeConfiguration<SaasOfferingVersionLimit>
{
    public void Configure(EntityTypeBuilder<SaasOfferingVersionLimit> builder)
    {
        builder.ConfigureEntity("saas_offering_version_limits");
        builder.Property(value => value.MetricCode).HasMaxLength(120);
        builder.HasIndex(value => new { value.OfferingVersionId, value.MetricCode }).IsUnique();
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.OfferingVersionId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<SaasFeatureLimitDefinition>().WithMany().HasPrincipalKey(value => value.MetricCode).HasForeignKey(value => value.MetricCode).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_saas_offering_version_limits_value", "limit_value >= 0"));
    }
}

internal sealed class TenantSaasSubscriptionConfiguration : IEntityTypeConfiguration<TenantSaasSubscription>
{
    public void Configure(EntityTypeBuilder<TenantSaasSubscription> builder)
    {
        builder.ConfigureTenantEntity("tenant_saas_subscriptions");
        builder.ConfigureTimestamps();
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.LifecycleVersion).IsConcurrencyToken();
        builder.Property(value => value.Metadata).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.Status, value.CurrentPeriodEnd });
        builder.HasIndex(value => value.TenantId).IsUnique().HasFilter("status in ('trial', 'active', 'past_due', 'suspended')");
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.BaseOfferingVersionId).OnDelete(DeleteBehavior.Restrict);
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.ScheduledBaseOfferingVersionId).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_tenant_saas_subscriptions_period", "current_period_end > current_period_start and current_period_start >= starts_at"));
    }
}

internal sealed class TenantSaasSubscriptionItemConfiguration : IEntityTypeConfiguration<TenantSaasSubscriptionItem>
{
    public void Configure(EntityTypeBuilder<TenantSaasSubscriptionItem> builder)
    {
        builder.ConfigureTenantEntity("tenant_saas_subscription_items");
        builder.ConfigureTimestamps();
        builder.Property(value => value.ItemType).HasSnakeCaseEnum();
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.HasIndex(value => new { value.TenantId, value.SubscriptionId, value.OfferingVersionId, value.Status });
        builder.HasIndex(value => new { value.TenantId, value.SubscriptionId, value.ItemType })
            .HasDatabaseName("ux_tenant_saas_subscription_items_current_base")
            .IsUnique()
            .HasFilter("item_type = 'base_plan' and status = 'active'");
        builder.HasIndex(value => new { value.TenantId, value.SubscriptionId, value.Status })
            .HasDatabaseName("ux_tenant_saas_subscription_items_scheduled_base")
            .IsUnique()
            .HasFilter("item_type = 'base_plan' and status = 'scheduled'");
        builder.HasOne<TenantSaasSubscription>().WithMany()
            .HasForeignKey(value => new { value.TenantId, value.SubscriptionId })
            .HasPrincipalKey(value => new { value.TenantId, value.Id })
            .OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.OfferingVersionId).OnDelete(DeleteBehavior.Restrict);
        builder.HasOne<PlatformBillingOrderItem>().WithMany()
            .HasForeignKey(value => new { value.TenantId, value.SourceOrderItemId })
            .HasPrincipalKey(value => new { value.TenantId, value.Id })
            .OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_tenant_saas_subscription_items_period", "ends_at > starts_at"));
    }
}

internal sealed class TenantFeatureOverrideConfiguration : IEntityTypeConfiguration<TenantFeatureOverride>
{
    public void Configure(EntityTypeBuilder<TenantFeatureOverride> builder)
    {
        builder.ConfigureTenantEntity("tenant_feature_overrides");
        builder.ConfigureTimestamps();
        builder.Property(value => value.FeatureCode).HasMaxLength(120);
        builder.Property(value => value.Mode).HasSnakeCaseEnum();
        builder.Property(value => value.Reason).HasMaxLength(1000);
        builder.HasIndex(value => new { value.TenantId, value.FeatureCode }).IsUnique();
        builder.HasOne<SaasFeature>().WithMany().HasPrincipalKey(value => value.Code).HasForeignKey(value => value.FeatureCode).OnDelete(DeleteBehavior.Restrict);
    }
}

internal sealed class TenantFeatureUsageConfiguration : IEntityTypeConfiguration<TenantFeatureUsage>
{
    public void Configure(EntityTypeBuilder<TenantFeatureUsage> builder)
    {
        builder.ConfigureTenantEntity("tenant_feature_usage");
        builder.ConfigureTimestamps();
        builder.Property(value => value.MetricCode).HasMaxLength(120);
        builder.Property(value => value.Version).IsConcurrencyToken();
        builder.HasIndex(value => new { value.TenantId, value.MetricCode, value.PeriodStart, value.PeriodEnd }).IsUnique();
        builder.HasOne<SaasFeatureLimitDefinition>().WithMany().HasPrincipalKey(value => value.MetricCode).HasForeignKey(value => value.MetricCode).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_tenant_feature_usage_values", "used_value >= 0 and limit_value_snapshot >= 0");
            table.HasCheckConstraint("ck_tenant_feature_usage_period", "period_end > period_start");
        });
    }
}

internal sealed class PlatformBillingQuoteConfiguration : IEntityTypeConfiguration<PlatformBillingQuote>
{
    public void Configure(EntityTypeBuilder<PlatformBillingQuote> builder)
    {
        builder.ConfigureTenantEntity("platform_billing_quotes");
        builder.ConfigureTimestamps();
        builder.Property(value => value.QuoteNo).HasMaxLength(100);
        builder.Property(value => value.IdempotencyKey).HasMaxLength(200);
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.Purpose).HasSnakeCaseEnum();
        builder.Property(value => value.Currency).HasMaxLength(10);
        builder.Property(value => value.FeatureSnapshot).IsJson("[]");
        builder.Property(value => value.LimitSnapshot).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.QuoteNo }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.IdempotencyKey }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.Status, value.ExpiresAt });
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_quotes_amounts", "original_amount_cents >= 0 and discount_amount_cents >= 0 and total_amount_cents >= 0 and total_amount_cents = original_amount_cents - discount_amount_cents"));
    }
}

internal sealed class PlatformBillingQuoteItemConfiguration : IEntityTypeConfiguration<PlatformBillingQuoteItem>
{
    public void Configure(EntityTypeBuilder<PlatformBillingQuoteItem> builder)
    {
        builder.ConfigureEntity("platform_billing_quote_items");
        builder.HasAlternateKey(value => new { value.TenantId, value.Id });
        builder.Property(value => value.ItemType).HasSnakeCaseEnum();
        builder.Property(value => value.Snapshot).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.QuoteId, value.OfferingVersionId }).IsUnique();
        builder.HasOne<Tenant>().WithMany().HasForeignKey(value => value.TenantId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<PlatformBillingQuote>().WithMany().HasForeignKey(value => new { value.TenantId, value.QuoteId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.OfferingVersionId).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_quote_items_amounts", "quantity > 0 and unit_amount_cents >= 0 and amount_cents >= 0"));
    }
}

internal sealed class PlatformBillingOrderConfiguration : IEntityTypeConfiguration<PlatformBillingOrder>
{
    public void Configure(EntityTypeBuilder<PlatformBillingOrder> builder)
    {
        builder.ConfigureTenantEntity("platform_billing_orders");
        builder.ConfigureTimestamps();
        builder.Property(value => value.OrderNo).HasMaxLength(100);
        builder.Property(value => value.IdempotencyKey).HasMaxLength(200);
        builder.Property(value => value.Purpose).HasSnakeCaseEnum();
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.Currency).HasMaxLength(10);
        builder.Property(value => value.Snapshot).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.OrderNo }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.IdempotencyKey }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.Status, value.CreatedAt });
        builder.HasOne<PlatformBillingQuote>().WithMany().HasForeignKey(value => new { value.TenantId, value.QuoteId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_orders_amounts", "original_amount_cents >= 0 and discount_amount_cents >= 0 and total_amount_cents >= 0 and total_amount_cents = original_amount_cents - discount_amount_cents"));
    }
}

internal sealed class PlatformBillingOrderItemConfiguration : IEntityTypeConfiguration<PlatformBillingOrderItem>
{
    public void Configure(EntityTypeBuilder<PlatformBillingOrderItem> builder)
    {
        builder.ConfigureEntity("platform_billing_order_items");
        builder.HasAlternateKey(value => new { value.TenantId, value.Id });
        builder.Property(value => value.ItemType).HasSnakeCaseEnum();
        builder.Property(value => value.Snapshot).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.OrderId, value.OfferingVersionId }).IsUnique();
        builder.HasOne<Tenant>().WithMany().HasForeignKey(value => value.TenantId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<PlatformBillingOrder>().WithMany().HasForeignKey(value => new { value.TenantId, value.OrderId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<SaasOfferingVersion>().WithMany().HasForeignKey(value => value.OfferingVersionId).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_order_items_amounts", "quantity > 0 and unit_amount_cents >= 0 and amount_cents >= 0"));
    }
}

internal sealed class PlatformBillingPaymentConfiguration : IEntityTypeConfiguration<PlatformBillingPayment>
{
    public void Configure(EntityTypeBuilder<PlatformBillingPayment> builder)
    {
        builder.ConfigureTenantEntity("platform_billing_payments");
        builder.ConfigureTimestamps();
        builder.Property(value => value.PaymentNo).HasMaxLength(100);
        builder.Property(value => value.IdempotencyKey).HasMaxLength(200);
        builder.Property(value => value.Provider).HasMaxLength(50);
        builder.Property(value => value.Method).HasMaxLength(50);
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.ProviderTradeNo).HasMaxLength(200);
        builder.Property(value => value.ClientPayload).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.PaymentNo }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.IdempotencyKey }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.OrderId, value.Status });
        builder.HasOne<PlatformBillingOrder>().WithMany().HasForeignKey(value => new { value.TenantId, value.OrderId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Cascade);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_payments_amount", "amount_cents >= 0"));
    }
}

internal sealed class PlatformBillingPaymentEventConfiguration : IEntityTypeConfiguration<PlatformBillingPaymentEvent>
{
    public void Configure(EntityTypeBuilder<PlatformBillingPaymentEvent> builder)
    {
        builder.ConfigureEntity("platform_billing_payment_events");
        builder.HasAlternateKey(value => new { value.TenantId, value.Id });
        builder.Property(value => value.Provider).HasMaxLength(50);
        builder.Property(value => value.ProviderEventId).HasMaxLength(200);
        builder.Property(value => value.EventType).HasMaxLength(100);
        builder.Property(value => value.Payload).IsJson("{}");
        builder.Property(value => value.CreatedAt).HasDefaultValueSql("now()");
        builder.HasIndex(value => new { value.TenantId, value.Provider, value.ProviderEventId }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.PaymentId, value.CreatedAt });
        builder.HasOne<Tenant>().WithMany().HasForeignKey(value => value.TenantId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<PlatformBillingPayment>().WithMany().HasForeignKey(value => new { value.TenantId, value.PaymentId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class PlatformBillingRefundConfiguration : IEntityTypeConfiguration<PlatformBillingRefund>
{
    public void Configure(EntityTypeBuilder<PlatformBillingRefund> builder)
    {
        builder.ConfigureTenantEntity("platform_billing_refunds");
        builder.ConfigureTimestamps();
        builder.Property(value => value.RefundNo).HasMaxLength(100);
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.Reason).HasMaxLength(1000);
        builder.Property(value => value.ProviderRefundNo).HasMaxLength(200);
        builder.HasIndex(value => new { value.TenantId, value.RefundNo }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.OrderId, value.Status });
        builder.HasOne<PlatformBillingOrder>().WithMany().HasForeignKey(value => new { value.TenantId, value.OrderId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Restrict);
        builder.HasOne<PlatformBillingPayment>().WithMany().HasForeignKey(value => new { value.TenantId, value.PaymentId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_refunds_amount", "amount_cents > 0"));
    }
}

internal sealed class PlatformBillingInvoiceConfiguration : IEntityTypeConfiguration<PlatformBillingInvoice>
{
    public void Configure(EntityTypeBuilder<PlatformBillingInvoice> builder)
    {
        builder.ConfigureTenantEntity("platform_billing_invoices");
        builder.ConfigureTimestamps();
        builder.Property(value => value.InvoiceNo).HasMaxLength(100);
        builder.Property(value => value.Status).HasSnakeCaseEnum();
        builder.Property(value => value.Currency).HasMaxLength(10);
        builder.Property(value => value.BillingProfileSnapshot).IsJson("{}");
        builder.HasIndex(value => new { value.TenantId, value.InvoiceNo }).IsUnique();
        builder.HasIndex(value => new { value.TenantId, value.Status, value.DueDate });
        builder.HasOne<PlatformBillingOrder>().WithMany().HasForeignKey(value => new { value.TenantId, value.OrderId }).HasPrincipalKey(value => new { value.TenantId, value.Id }).OnDelete(DeleteBehavior.Restrict);
        builder.ToTable(table => table.HasCheckConstraint("ck_platform_billing_invoices_amount", "total_amount_cents >= 0"));
    }
}
