using MemberCenter.Domain.Entities;
using MemberCenter.Infrastructure.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace MemberCenter.Infrastructure.Persistence;

public class MemberCenterDbContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
{
    public MemberCenterDbContext(DbContextOptions<MemberCenterDbContext> options)
        : base(options)
    {
    }

    public DbSet<Tenant> Tenants => Set<Tenant>();
    public DbSet<NewsletterList> NewsletterLists => Set<NewsletterList>();
    public DbSet<NewsletterSubscription> NewsletterSubscriptions => Set<NewsletterSubscription>();
    public DbSet<EmailBlacklist> EmailBlacklist => Set<EmailBlacklist>();
    public DbSet<EmailVerification> EmailVerifications => Set<EmailVerification>();
    public DbSet<UnsubscribeToken> UnsubscribeTokens => Set<UnsubscribeToken>();
    public DbSet<AuditLog> AuditLogs => Set<AuditLog>();
    public DbSet<SystemFlag> SystemFlags => Set<SystemFlag>();

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.UseOpenIddict();

        builder.Entity<Tenant>(entity =>
        {
            entity.ToTable("tenants");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Name).IsRequired();
            entity.Property(x => x.Status).IsRequired().HasDefaultValue("active");
            entity.Property(x => x.Domains).HasColumnType("text[]");
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
        });

        builder.Entity<NewsletterList>(entity =>
        {
            entity.ToTable("newsletter_lists");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Name).IsRequired();
            entity.Property(x => x.Status).IsRequired().HasDefaultValue("active");
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
            entity.HasOne(x => x.Tenant)
                .WithMany(t => t.NewsletterLists)
                .HasForeignKey(x => x.TenantId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        builder.Entity<NewsletterSubscription>(entity =>
        {
            entity.ToTable("newsletter_subscriptions");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Email).IsRequired();
            entity.Property(x => x.Status).IsRequired().HasDefaultValue("pending");
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
            entity.Property(x => x.Preferences)
                .HasColumnType("jsonb")
                .HasConversion(
                    v => v.RootElement.GetRawText(),
                    v => System.Text.Json.JsonDocument.Parse(v, new System.Text.Json.JsonDocumentOptions()));
            entity.HasIndex(x => x.Email).HasDatabaseName("idx_newsletter_subscriptions_email");
            entity.HasIndex(x => x.ListId).HasDatabaseName("idx_newsletter_subscriptions_list_id");
            entity.HasIndex(x => new { x.ListId, x.Email }).IsUnique();
            entity.HasOne(x => x.List)
                .WithMany(l => l.Subscriptions)
                .HasForeignKey(x => x.ListId)
                .OnDelete(DeleteBehavior.Cascade);
            entity.HasOne<ApplicationUser>()
                .WithMany()
                .HasForeignKey(x => x.UserId)
                .OnDelete(DeleteBehavior.SetNull);
        });

        builder.Entity<EmailBlacklist>(entity =>
        {
            entity.ToTable("email_blacklist");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Email).IsRequired();
            entity.Property(x => x.Reason).IsRequired();
            entity.Property(x => x.BlacklistedAt).HasDefaultValueSql("now()");
            entity.Property(x => x.BlacklistedBy).IsRequired();
            entity.HasIndex(x => x.Email).IsUnique();
        });

        builder.Entity<EmailVerification>(entity =>
        {
            entity.ToTable("email_verifications");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Email).IsRequired();
            entity.Property(x => x.TokenHash).IsRequired();
            entity.Property(x => x.Purpose).IsRequired();
            entity.HasIndex(x => x.Email).HasDatabaseName("idx_email_verifications_email");
            entity.HasOne<Tenant>()
                .WithMany()
                .HasForeignKey(x => x.TenantId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        builder.Entity<UnsubscribeToken>(entity =>
        {
            entity.ToTable("unsubscribe_tokens");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.TokenHash).IsRequired();
            entity.HasOne(x => x.Subscription)
                .WithMany()
                .HasForeignKey(x => x.SubscriptionId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        builder.Entity<AuditLog>(entity =>
        {
            entity.ToTable("audit_logs");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.ActorType).IsRequired();
            entity.Property(x => x.Action).IsRequired();
            entity.Property(x => x.Payload)
                .HasColumnType("jsonb")
                .HasConversion(
                    v => v.RootElement.GetRawText(),
                    v => System.Text.Json.JsonDocument.Parse(v, new System.Text.Json.JsonDocumentOptions()));
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
        });

        builder.Entity<SystemFlag>(entity =>
        {
            entity.ToTable("system_flags");
            entity.HasKey(x => x.Id);
            entity.Property(x => x.Key).IsRequired();
            entity.Property(x => x.Value).IsRequired();
            entity.Property(x => x.UpdatedAt).HasDefaultValueSql("now()");
            entity.HasIndex(x => x.Key).IsUnique();
        });

        builder.Entity<ApplicationUser>(entity =>
        {
            entity.ToTable("users");
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
            entity.Property(x => x.IsBlacklisted).HasDefaultValue(false);
        });

        builder.Entity<ApplicationRole>(entity =>
        {
            entity.ToTable("roles");
            entity.Property(x => x.CreatedAt).HasDefaultValueSql("now()");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserRole<Guid>>(entity =>
        {
            entity.ToTable("user_roles");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserClaim<Guid>>(entity =>
        {
            entity.ToTable("user_claims");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityRoleClaim<Guid>>(entity =>
        {
            entity.ToTable("role_claims");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>>(entity =>
        {
            entity.ToTable("user_logins");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>>(entity =>
        {
            entity.ToTable("user_tokens");
        });

        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserLogin<Guid>>().HasKey(l => new { l.LoginProvider, l.ProviderKey });
        builder.Entity<Microsoft.AspNetCore.Identity.IdentityUserToken<Guid>>().HasKey(t => new { t.UserId, t.LoginProvider, t.Name });
    }
}
