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

namespace Tiku.Infrastructure.Persistence.Configurations;

internal sealed class ReferralTrackConfiguration : IEntityTypeConfiguration<ReferralTrack>
{
    public void Configure(EntityTypeBuilder<ReferralTrack> builder)
    {
        builder.ConfigureTenantEntity("referral_tracks");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.LegacyId).HasMaxLength(64);
        builder.Property(entity => entity.EventType).HasMaxLength(100);
        builder.Property(entity => entity.RefCode).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Source).HasMaxLength(100);
        builder.Property(entity => entity.IpAddress).HasMaxLength(100);
        builder.Property(entity => entity.UserAgent).HasMaxLength(1024);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.LeadId, entity.CreatedAt });
        builder.HasIndex(entity => new { entity.TenantId, entity.RefCode, entity.EventType, entity.CreatedAt });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReferrerUserId).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.TargetUserId).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<ReferralLead>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.LeadId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class ReferralCodeConfiguration : IEntityTypeConfiguration<ReferralCode>
{
    public void Configure(EntityTypeBuilder<ReferralCode> builder)
    {
        builder.ConfigureTenantEntity("referral_codes");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.Code).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Channel).HasMaxLength(100);
        builder.Property(entity => entity.LandingPath).HasMaxLength(2048);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.UserId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.Code }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.Code, entity.Status });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
    }
}

internal sealed class ReferralLeadConfiguration : IEntityTypeConfiguration<ReferralLead>
{
    public void Configure(EntityTypeBuilder<ReferralLead> builder)
    {
        builder.ConfigureTenantEntity("referral_leads");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.RefCode).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Source).HasMaxLength(100);
        builder.Property(entity => entity.BindType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.AssignmentMode).HasNullableSnakeCaseEnum();
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.Property(entity => entity.BoundAt).HasDefaultValueSql("now()");
        builder.HasIndex(entity => new { entity.TenantId, entity.StudentUserId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.ReferrerUserId, entity.BoundAt });
        builder.HasIndex(entity => new { entity.TenantId, entity.AssignedToUserId, entity.Status, entity.BoundAt });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.StudentUserId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReferrerUserId).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.AssignedToUserId).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.AssignedBy).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<ReferralTrack>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.FirstTrackId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class ReferralTeamEdgeConfiguration : IEntityTypeConfiguration<ReferralTeamEdge>
{
    public void Configure(EntityTypeBuilder<ReferralTeamEdge> builder)
    {
        builder.ConfigureTenantEntity("referral_team_edges");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.RelationType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.MemberUserId, entity.RelationType }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.LeaderUserId, entity.Status });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.MemberUserId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.LeaderUserId).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class ReferralQrcodeConfiguration : IEntityTypeConfiguration<ReferralQrcode>
{
    public void Configure(EntityTypeBuilder<ReferralQrcode> builder)
    {
        builder.ConfigureTenantEntity("referral_qrcodes");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.RefCode).HasColumnType("citext").HasMaxLength(100);
        builder.Property(entity => entity.Scene).HasMaxLength(300);
        builder.Property(entity => entity.Page).HasMaxLength(300);
        builder.Property(entity => entity.Provider).HasMaxLength(100);
        builder.Property(entity => entity.QrcodeUrl).HasMaxLength(2048);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.Provider, entity.Scene, entity.Page }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.RefCode, entity.Status });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class CrmConfigConfiguration : IEntityTypeConfiguration<CrmConfig>
{
    public void Configure(EntityTypeBuilder<CrmConfig> builder)
    {
        builder.ConfigureTenantEntity("crm_config");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.Url).HasMaxLength(2048);
        builder.Property(entity => entity.SecretRef).HasMaxLength(300);
        builder.Property(entity => entity.FormName).HasMaxLength(200);
        builder.Property(entity => entity.ExamType).HasMaxLength(100);
        builder.Property(entity => entity.AssignmentMode).HasSnakeCaseEnum();
        builder.Property(entity => entity.AssignmentPool).IsJson("[]");
        builder.Property(entity => entity.AssignmentConfig).IsJson("{}");
        builder.HasIndex(entity => entity.TenantId).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.AssignmentMode });
    }
}

internal sealed class CrmWebhookQueueItemConfiguration : IEntityTypeConfiguration<CrmWebhookQueueItem>
{
    public void Configure(EntityTypeBuilder<CrmWebhookQueueItem> builder)
    {
        builder.ConfigureTenantEntity("crm_webhook_queue");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.LegacyId).HasMaxLength(64);
        builder.Property(entity => entity.RecordId).HasMaxLength(200);
        builder.Property(entity => entity.LeadId).HasMaxLength(200);
        builder.Property(entity => entity.Source).HasMaxLength(200);
        builder.Property(entity => entity.Provider).HasMaxLength(100);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.IdempotencyKey).HasMaxLength(200);
        builder.Property(entity => entity.TargetUrl).HasMaxLength(2048);
        builder.Property(entity => entity.Payload).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.RecordId })
            .IsUnique()
            .HasFilter("record_id is not null");
        builder.HasIndex(entity => new { entity.TenantId, entity.IdempotencyKey })
            .IsUnique()
            .HasFilter("idempotency_key is not null");
        builder.HasIndex(entity => new { entity.TenantId, entity.Status, entity.ScheduledAt, entity.NextAttemptAt });
        builder.HasIndex(entity => new { entity.TenantId, entity.RecordId, entity.CreatedAt })
            .HasFilter("record_id is not null");
        builder.HasIndex(entity => new { entity.TenantId, entity.Source, entity.CreatedAt })
            .HasFilter("source = 'tenant.student.crm_push'");
        builder.ToTable(table => table.HasCheckConstraint("ck_crm_webhook_queue_attempts", "attempts >= 0"));
    }
}

internal sealed class CrmWebhookLogConfiguration : IEntityTypeConfiguration<CrmWebhookLog>
{
    public void Configure(EntityTypeBuilder<CrmWebhookLog> builder)
    {
        builder.ConfigureTenantEntity("crm_webhook_log");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.LegacyId).HasMaxLength(64);
        builder.Property(entity => entity.RecordId).HasMaxLength(200);
        builder.Property(entity => entity.LeadId).HasMaxLength(200);
        builder.Property(entity => entity.Outcome).HasMaxLength(100);
        builder.Property(entity => entity.RequestPayload).IsJson("{}");
        builder.Property(entity => entity.ResponseSummary).HasMaxLength(2000);
        builder.HasIndex(entity => new { entity.TenantId, entity.LegacyId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.RecordId, entity.CreatedAt });
    }
}

internal sealed class TenantCommissionSettingConfiguration : IEntityTypeConfiguration<TenantCommissionSetting>
{
    public void Configure(EntityTypeBuilder<TenantCommissionSetting> builder)
    {
        builder.ConfigureTenantEntity("tenant_commission_settings");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.DefaultRate).HasPrecision(6, 4);
        builder.Property(entity => entity.SettlementCycle).HasSnakeCaseEnum();
        builder.Property(entity => entity.Config).IsJson("{}");
        builder.HasIndex(entity => entity.TenantId).IsUnique();
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_tenant_commission_settings_default_rate", "default_rate >= 0 and default_rate <= 1");
            table.HasCheckConstraint("ck_tenant_commission_settings_min_settlement", "min_settlement_cents >= 0");
        });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UpdatedBy).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class CommissionSettlementConfiguration : IEntityTypeConfiguration<CommissionSettlement>
{
    public void Configure(EntityTypeBuilder<CommissionSettlement> builder)
    {
        builder.ConfigureTenantEntity("commission_settlements");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.SettlementNo).HasMaxLength(100);
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.DefaultRate).HasPrecision(6, 4);
        builder.Property(entity => entity.EffectiveRate).HasPrecision(6, 4);
        builder.Property(entity => entity.PaymentMethod).HasMaxLength(100);
        builder.Property(entity => entity.PaymentAccount).HasMaxLength(200);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.SettlementNo }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.ReferrerUserId, entity.PeriodStart, entity.PeriodEnd })
            .IsUnique()
            .HasDatabaseName("ux_commission_settlements_referrer_period");
        builder.HasIndex(entity => new { entity.TenantId, entity.ReferrerUserId, entity.PeriodStart })
            .HasDatabaseName("ix_commission_settlements_referrer_start");
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_commission_settlements_counts", "source_count >= 0 and paid_user_count >= 0");
            table.HasCheckConstraint("ck_commission_settlements_amounts", "gross_amount_cents >= 0 and commission_amount_cents >= 0");
            table.HasCheckConstraint("ck_commission_settlements_rates", "default_rate >= 0 and default_rate <= 1 and (effective_rate is null or (effective_rate >= 0 and effective_rate <= 1))");
            table.HasCheckConstraint("ck_commission_settlements_period", "period_end >= period_start");
        });
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReferrerUserId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.GeneratedBy).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReviewedBy).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.PaidBy).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class CommissionSettlementItemConfiguration : IEntityTypeConfiguration<CommissionSettlementItem>
{
    public void Configure(EntityTypeBuilder<CommissionSettlementItem> builder)
    {
        builder.ConfigureTenantEntity("commission_settlement_items");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.SourceType).HasSnakeCaseEnum();
        builder.Property(entity => entity.SourceNo).HasMaxLength(100);
        builder.Property(entity => entity.CommissionRate).HasPrecision(6, 4);
        builder.Property(entity => entity.RateSource).HasSnakeCaseEnum();
        builder.Property(entity => entity.AttributionType).HasMaxLength(100);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.SourceType, entity.SourceId }).IsUnique();
        builder.HasIndex(entity => new { entity.TenantId, entity.ReferrerUserId, entity.SourcePaidAt });
        builder.HasIndex(entity => new { entity.TenantId, entity.SettlementId });
        builder.ToTable(table =>
        {
            table.HasCheckConstraint("ck_commission_settlement_items_amounts", "gross_amount_cents >= 0 and commission_amount_cents >= 0");
            table.HasCheckConstraint("ck_commission_settlement_items_rate", "commission_rate >= 0 and commission_rate <= 1");
        });
        builder.HasOne<CommissionSettlement>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.SettlementId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReferrerUserId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.StudentUserId).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class CommissionSettlementProofConfiguration : IEntityTypeConfiguration<CommissionSettlementProof>
{
    public void Configure(EntityTypeBuilder<CommissionSettlementProof> builder)
    {
        builder.ConfigureTenantEntity("commission_settlement_proofs");
        builder.ConfigureTimestamps();
        builder.Property(entity => entity.ProofType).HasSnakeCaseEnum();
        builder.Property(entity => entity.Status).HasSnakeCaseEnum();
        builder.Property(entity => entity.Title).HasMaxLength(200);
        builder.Property(entity => entity.ExternalUrl).HasMaxLength(2048);
        builder.Property(entity => entity.PaymentMethod).HasMaxLength(100);
        builder.Property(entity => entity.PaymentAccount).HasMaxLength(200);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.HasIndex(entity => new { entity.TenantId, entity.SettlementId, entity.Status, entity.CreatedAt });
        builder.ToTable(table => table.HasCheckConstraint(
            "ck_commission_settlement_proofs_amount",
            "amount_cents is null or amount_cents >= 0"));
        builder.HasOne<CommissionSettlement>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.SettlementId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<ContentAsset>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.AssetId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.SubmittedBy).OnDelete(DeleteBehavior.SetNull);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ReviewedBy).OnDelete(DeleteBehavior.SetNull);
    }
}

internal sealed class CommissionSettlementExportEventConfiguration : IEntityTypeConfiguration<CommissionSettlementExportEvent>
{
    public void Configure(EntityTypeBuilder<CommissionSettlementExportEvent> builder)
    {
        builder.ToTable("commission_settlement_export_events");
        builder.HasKey(entity => entity.Id);
        builder.Property(entity => entity.Id).HasDefaultValueSql("gen_random_uuid()");
        builder.Property(entity => entity.ExportFormat).HasMaxLength(20);
        builder.Property(entity => entity.Filename).HasMaxLength(500);
        builder.Property(entity => entity.ContentSha256).HasMaxLength(128);
        builder.Property(entity => entity.Metadata).IsJson("{}");
        builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()");
        builder.HasIndex(entity => new { entity.TenantId, entity.SettlementId, entity.CreatedAt });
        builder.ToTable(table => table.HasCheckConstraint("ck_commission_export_events_rows", "row_count >= 0"));
        builder.HasOne<Tenant>().WithMany().HasForeignKey(entity => entity.TenantId).OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<CommissionSettlement>().WithMany()
            .HasForeignKey(entity => new { entity.TenantId, entity.SettlementId })
            .HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
            .OnDelete(DeleteBehavior.Cascade);
        builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ExportedBy).OnDelete(DeleteBehavior.SetNull);
    }
}
