using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using TakeoutSaaS.Domain.Dictionary.Entities;
using TakeoutSaaS.Domain.Dictionary.ValueObjects;
using TakeoutSaaS.Domain.SystemParameters.Entities;
using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Infrastructure.Dictionary.Persistence;

/// <summary>
/// 参数字典 DbContext：承载字典与系统参数。
/// </summary>
public sealed class DictionaryDbContext(
    DbContextOptions<DictionaryDbContext> options,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor? currentUserAccessor = null,
    IIdGenerator? idGenerator = null)
    : TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
    /// <summary>
    /// 字典分组集合。
    /// </summary>
    public DbSet<DictionaryGroup> DictionaryGroups => Set<DictionaryGroup>();

    /// <summary>
    /// 字典项集合。
    /// </summary>
    public DbSet<DictionaryItem> DictionaryItems => Set<DictionaryItem>();

    /// <summary>
    /// 租户字典覆盖集合。
    /// </summary>
    public DbSet<TenantDictionaryOverride> TenantDictionaryOverrides => Set<TenantDictionaryOverride>();

    /// <summary>
    /// 字典导入日志集合。
    /// </summary>
    public DbSet<DictionaryImportLog> DictionaryImportLogs => Set<DictionaryImportLog>();

    /// <summary>
    /// 缓存失效日志集合。
    /// </summary>
    public DbSet<CacheInvalidationLog> CacheInvalidationLogs => Set<CacheInvalidationLog>();

    /// <summary>
    /// 字典标签覆盖集合。
    /// </summary>
    public DbSet<DictionaryLabelOverride> DictionaryLabelOverrides => Set<DictionaryLabelOverride>();

    /// <summary>
    /// 系统参数集合。
    /// </summary>
    public DbSet<SystemParameter> SystemParameters => Set<SystemParameter>();

    /// <summary>
    /// 配置实体模型。
    /// </summary>
    /// <param name="modelBuilder">模型构建器。</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        var provider = Database.ProviderName;
        var isSqlite = provider != null && provider.Contains("Sqlite", StringComparison.OrdinalIgnoreCase);
        ConfigureGroup(modelBuilder.Entity<DictionaryGroup>(), isSqlite);
        ConfigureItem(modelBuilder.Entity<DictionaryItem>(), isSqlite);
        ConfigureOverride(modelBuilder.Entity<TenantDictionaryOverride>());
        ConfigureLabelOverride(modelBuilder.Entity<DictionaryLabelOverride>());
        ConfigureImportLog(modelBuilder.Entity<DictionaryImportLog>());
        ConfigureCacheInvalidationLog(modelBuilder.Entity<CacheInvalidationLog>());
        ConfigureSystemParameter(modelBuilder.Entity<SystemParameter>());
        ApplyTenantQueryFilters(modelBuilder);
    }

    /// <summary>
    /// 配置字典分组。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureGroup(EntityTypeBuilder<DictionaryGroup> builder, bool isSqlite)
    {
        builder.ToTable("dictionary_groups");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.Code)
            .HasConversion(code => code.Value, value => new DictionaryCode(value))
            .HasMaxLength(64)
            .IsRequired();
        builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Scope).HasConversion<int>().IsRequired();
        builder.Property(x => x.AllowOverride).HasDefaultValue(false);
        builder.Property(x => x.Description).HasMaxLength(512);
        builder.Property(x => x.IsEnabled).HasDefaultValue(true);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        var rowVersion = builder.Property(x => x.RowVersion)
            .IsConcurrencyToken();

        if (isSqlite)
        {
            rowVersion.ValueGeneratedNever();
            rowVersion.HasColumnType("BLOB");
        }
        else
        {
            rowVersion.IsRowVersion().HasColumnType("bytea");
        }

        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.Code })
            .IsUnique()
            .HasFilter("\"DeletedAt\" IS NULL");
        builder.HasIndex(x => new { x.TenantId, x.Scope, x.IsEnabled });
    }

    /// <summary>
    /// 配置字典项。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureItem(EntityTypeBuilder<DictionaryItem> builder, bool isSqlite)
    {
        builder.ToTable("dictionary_items");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.GroupId).IsRequired();
        builder.Property(x => x.Key).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Value).HasColumnType("jsonb").IsRequired();
        builder.Property(x => x.Description).HasMaxLength(512);
        builder.Property(x => x.SortOrder).HasDefaultValue(100);
        builder.Property(x => x.IsEnabled).HasDefaultValue(true);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        var rowVersion = builder.Property(x => x.RowVersion)
            .IsConcurrencyToken();

        if (isSqlite)
        {
            rowVersion.ValueGeneratedNever();
            rowVersion.HasColumnType("BLOB");
        }
        else
        {
            rowVersion.IsRowVersion().HasColumnType("bytea");
        }

        builder.HasOne(x => x.Group)
            .WithMany(g => g.Items)
            .HasForeignKey(x => x.GroupId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.GroupId, x.Key })
            .IsUnique()
            .HasFilter("\"DeletedAt\" IS NULL");
        builder.HasIndex(x => new { x.GroupId, x.IsEnabled, x.SortOrder });
    }

    /// <summary>
    /// 配置租户字典覆盖。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureOverride(EntityTypeBuilder<TenantDictionaryOverride> builder)
    {
        builder.ToTable("tenant_dictionary_overrides");
        builder.HasKey(x => new { x.TenantId, x.SystemDictionaryGroupId });
        builder.Property(x => x.OverrideEnabled).HasDefaultValue(false);
        builder.Property(x => x.HiddenSystemItemIds).HasColumnType("bigint[]");
        builder.Property(x => x.CustomSortOrder).HasColumnType("jsonb");
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        builder.HasIndex(x => x.HiddenSystemItemIds).HasMethod("gin");
    }

    /// <summary>
    /// 配置字典导入日志。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureImportLog(EntityTypeBuilder<DictionaryImportLog> builder)
    {
        builder.ToTable("dictionary_import_logs");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.OperatorId).IsRequired();
        builder.Property(x => x.DictionaryGroupCode).HasMaxLength(64).IsRequired();
        builder.Property(x => x.FileName).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Format).HasMaxLength(16).IsRequired();
        builder.Property(x => x.ErrorDetails).HasColumnType("jsonb");
        builder.Property(x => x.ProcessedAt).IsRequired();
        builder.Property(x => x.Duration).HasColumnType("interval");
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        builder.HasIndex(x => new { x.TenantId, x.ProcessedAt });
    }

    /// <summary>
    /// 配置缓存失效日志。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureCacheInvalidationLog(EntityTypeBuilder<CacheInvalidationLog> builder)
    {
        builder.ToTable("dictionary_cache_invalidation_logs");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.DictionaryCode).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Scope).HasConversion<int>().IsRequired();
        builder.Property(x => x.Operation).HasConversion<int>().IsRequired();
        builder.Property(x => x.Timestamp).IsRequired();
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        builder.HasIndex(x => new { x.TenantId, x.Timestamp });
    }

    /// <summary>
    /// 配置系统参数。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureSystemParameter(EntityTypeBuilder<SystemParameter> builder)
    {
        builder.ToTable("system_parameters");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.Key).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Value).HasColumnType("text").IsRequired();
        builder.Property(x => x.Description).HasMaxLength(512);
        builder.Property(x => x.SortOrder).HasDefaultValue(100);
        builder.Property(x => x.IsEnabled).HasDefaultValue(true);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.Key }).IsUnique();
    }

    /// <summary>
    /// 配置字典标签覆盖。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureLabelOverride(EntityTypeBuilder<DictionaryLabelOverride> builder)
    {
        builder.ToTable("dictionary_label_overrides", t => t.HasComment("字典标签覆盖配置。"));
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Id).HasComment("实体唯一标识。");
        builder.Property(x => x.TenantId).IsRequired().HasComment("所属租户 ID（覆盖目标租户）。");
        builder.Property(x => x.DictionaryItemId).IsRequired().HasComment("被覆盖的字典项 ID。");
        builder.Property(x => x.OriginalValue).HasColumnType("jsonb").IsRequired().HasComment("原始显示值（JSON 格式，多语言）。");
        builder.Property(x => x.OverrideValue).HasColumnType("jsonb").IsRequired().HasComment("覆盖后的显示值（JSON 格式，多语言）。");
        builder.Property(x => x.OverrideType).HasConversion<int>().IsRequired().HasComment("覆盖类型。");
        builder.Property(x => x.Reason).HasMaxLength(512).HasComment("覆盖原因/备注。");
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

        builder.HasOne(x => x.DictionaryItem)
            .WithMany()
            .HasForeignKey(x => x.DictionaryItemId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.DictionaryItemId })
            .IsUnique()
            .HasFilter("\"DeletedAt\" IS NULL");
        builder.HasIndex(x => new { x.TenantId, x.OverrideType });
    }
}
