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

namespace TakeoutSaaS.Infrastructure.Identity.Persistence;

/// <summary>
/// 身份认证 DbContext，带多租户过滤与审计字段处理。
/// </summary>
public sealed class IdentityDbContext(
    DbContextOptions<IdentityDbContext> options,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor? currentUserAccessor = null,
    IIdGenerator? idGenerator = null)
    : TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
    /// <summary>
    /// 管理后台用户集合。
    /// </summary>
    public DbSet<IdentityUser> IdentityUsers => Set<IdentityUser>();

    /// <summary>
    /// 小程序用户集合。
    /// </summary>
    public DbSet<MiniUser> MiniUsers => Set<MiniUser>();

    /// <summary>
    /// 角色集合。
    /// </summary>
    public DbSet<Role> Roles => Set<Role>();

    /// <summary>
    /// 角色模板集合（平台级）。
    /// </summary>
    public DbSet<RoleTemplate> RoleTemplates => Set<RoleTemplate>();

    /// <summary>
    /// 角色模板权限集合。
    /// </summary>
    public DbSet<RoleTemplatePermission> RoleTemplatePermissions => Set<RoleTemplatePermission>();

    /// <summary>
    /// 权限集合。
    /// </summary>
    public DbSet<Permission> Permissions => Set<Permission>();

    /// <summary>
    /// 用户-角色关系。
    /// </summary>
    public DbSet<UserRole> UserRoles => Set<UserRole>();

    /// <summary>
    /// 角色-权限关系。
    /// </summary>
    public DbSet<RolePermission> RolePermissions => Set<RolePermission>();

    /// <summary>
    /// 菜单定义集合。
    /// </summary>
    public DbSet<MenuDefinition> MenuDefinitions => Set<MenuDefinition>();

    /// <summary>
    /// 配置实体模型。
    /// </summary>
    /// <param name="modelBuilder">模型构建器。</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        ConfigureIdentityUser(modelBuilder.Entity<IdentityUser>());
        ConfigureMiniUser(modelBuilder.Entity<MiniUser>());
        ConfigureRole(modelBuilder.Entity<Role>());
        ConfigureRoleTemplate(modelBuilder.Entity<RoleTemplate>());
        ConfigureRoleTemplatePermission(modelBuilder.Entity<RoleTemplatePermission>());
        ConfigurePermission(modelBuilder.Entity<Permission>());
        ConfigureUserRole(modelBuilder.Entity<UserRole>());
        ConfigureRolePermission(modelBuilder.Entity<RolePermission>());
        ConfigureMenuDefinition(modelBuilder.Entity<MenuDefinition>());
        ApplyTenantQueryFilters(modelBuilder);
    }

    /// <summary>
    /// 配置管理后台用户实体。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureIdentityUser(EntityTypeBuilder<IdentityUser> builder)
    {
        builder.ToTable("identity_users");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Account).HasMaxLength(64).IsRequired();
        builder.Property(x => x.DisplayName).HasMaxLength(64).IsRequired();
        builder.Property(x => x.PasswordHash).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Avatar).HasMaxLength(256);
        builder.Property(x => x.TenantId).IsRequired();
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

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

    /// <summary>
    /// 配置小程序用户实体。
    /// </summary>
    /// <param name="builder">实体构建器。</param>
    private static void ConfigureMiniUser(EntityTypeBuilder<MiniUser> builder)
    {
        builder.ToTable("mini_users");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.OpenId).HasMaxLength(128).IsRequired();
        builder.Property(x => x.UnionId).HasMaxLength(128);
        builder.Property(x => x.Nickname).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Avatar).HasMaxLength(256);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);

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

    private static void ConfigureRole(EntityTypeBuilder<Role> builder)
    {
        builder.ToTable("roles");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Code).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Description).HasMaxLength(256);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);
        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
    }

    private static void ConfigurePermission(EntityTypeBuilder<Permission> builder)
    {
        builder.ToTable("permissions");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.ParentId).IsRequired();
        builder.Property(x => x.SortOrder).IsRequired();
        builder.Property(x => x.Type).HasMaxLength(16).IsRequired();
        builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Code).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Description).HasMaxLength(256);
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);
        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.ParentId, x.SortOrder });
        builder.HasIndex(x => new { x.TenantId, x.Code }).IsUnique();
    }

    private static void ConfigureRoleTemplate(EntityTypeBuilder<RoleTemplate> builder)
    {
        builder.ToTable("role_templates");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TemplateCode).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Name).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Description).HasMaxLength(256);
        builder.Property(x => x.IsActive).IsRequired();
        ConfigureAuditableEntity(builder);
        builder.HasIndex(x => x.TemplateCode).IsUnique();
    }

    private static void ConfigureRoleTemplatePermission(EntityTypeBuilder<RoleTemplatePermission> builder)
    {
        builder.ToTable("role_template_permissions");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.RoleTemplateId).IsRequired();
        builder.Property(x => x.PermissionCode).HasMaxLength(128).IsRequired();
        ConfigureAuditableEntity(builder);
        builder.HasIndex(x => new { x.RoleTemplateId, x.PermissionCode }).IsUnique();
    }

    private static void ConfigureUserRole(EntityTypeBuilder<UserRole> builder)
    {
        builder.ToTable("user_roles");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.UserId).IsRequired();
        builder.Property(x => x.RoleId).IsRequired();
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);
        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.UserId, x.RoleId }).IsUnique();
    }

    private static void ConfigureRolePermission(EntityTypeBuilder<RolePermission> builder)
    {
        builder.ToTable("role_permissions");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.RoleId).IsRequired();
        builder.Property(x => x.PermissionId).IsRequired();
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);
        builder.HasIndex(x => x.TenantId);
        builder.HasIndex(x => new { x.TenantId, x.RoleId, x.PermissionId }).IsUnique();
    }

    private static void ConfigureMenuDefinition(EntityTypeBuilder<MenuDefinition> builder)
    {
        builder.ToTable("menu_definitions");
        builder.HasKey(x => x.Id);
        builder.Property(x => x.TenantId).IsRequired();
        builder.Property(x => x.ParentId).IsRequired();
        builder.Property(x => x.Name).HasMaxLength(64).IsRequired();
        builder.Property(x => x.Path).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Component).HasMaxLength(256).IsRequired();
        builder.Property(x => x.Title).HasMaxLength(128).IsRequired();
        builder.Property(x => x.Icon).HasMaxLength(64);
        builder.Property(x => x.Link).HasMaxLength(512);
        builder.Property(x => x.SortOrder).IsRequired();
        builder.Property(x => x.RequiredPermissions).HasMaxLength(1024);
        builder.Property(x => x.MetaPermissions).HasMaxLength(1024);
        builder.Property(x => x.MetaRoles).HasMaxLength(1024);
        builder.Property(x => x.AuthListJson).HasColumnType("text");
        ConfigureAuditableEntity(builder);
        ConfigureSoftDeleteEntity(builder);
        builder.HasIndex(x => new { x.TenantId, x.ParentId, x.SortOrder });
    }
}
