using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Repositories;

namespace TakeoutSaaS.Infrastructure.Identity.Persistence;

/// <summary>
/// 角色模板仓储实现。
/// </summary>
public sealed class EfRoleTemplateRepository(IdentityDbContext dbContext) : IRoleTemplateRepository
{
    /// <summary>
    /// 获取全部角色模板，可选按启用状态过滤。
    /// </summary>
    /// <param name="isActive">是否启用过滤。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>角色模板列表。</returns>
    public Task<IReadOnlyList<RoleTemplate>> GetAllAsync(bool? isActive, CancellationToken cancellationToken = default)
    {
        // 1. 构建基础查询
        var query = dbContext.RoleTemplates.AsNoTracking();
        if (isActive.HasValue)
        {
            // 2. 按启用状态过滤
            query = query.Where(x => x.IsActive == isActive.Value);
        }

        // 3. 排序并返回
        return query
            .OrderBy(x => x.TemplateCode)
            .ToListAsync(cancellationToken)
            .ContinueWith(t => (IReadOnlyList<RoleTemplate>)t.Result, cancellationToken);
    }

    /// <summary>
    /// 根据模板编码获取角色模板。
    /// </summary>
    /// <param name="templateCode">模板编码。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>角色模板或 null。</returns>
    public Task<RoleTemplate?> FindByCodeAsync(string templateCode, CancellationToken cancellationToken = default)
    {
        // 1. 规范化编码
        var normalized = templateCode.Trim();
        // 2. 查询模板
        return dbContext.RoleTemplates.AsNoTracking().FirstOrDefaultAsync(x => x.TemplateCode == normalized, cancellationToken);
    }

    /// <summary>
    /// 获取指定模板的权限集合。
    /// </summary>
    /// <param name="roleTemplateId">模板 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>模板权限列表。</returns>
    public Task<IReadOnlyList<RoleTemplatePermission>> GetPermissionsAsync(long roleTemplateId, CancellationToken cancellationToken = default)
    {
        // 1. 查询模板权限
        return dbContext.RoleTemplatePermissions.AsNoTracking()
            .Where(x => x.RoleTemplateId == roleTemplateId)
            .ToListAsync(cancellationToken)
            .ContinueWith(t => (IReadOnlyList<RoleTemplatePermission>)t.Result, cancellationToken);
    }

    /// <summary>
    /// 获取多个模板的权限集合。
    /// </summary>
    /// <param name="roleTemplateIds">模板 ID 集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>模板到权限的字典。</returns>
    public async Task<IDictionary<long, IReadOnlyList<RoleTemplatePermission>>> GetPermissionsAsync(IEnumerable<long> roleTemplateIds, CancellationToken cancellationToken = default)
    {
        // 1. 去重 ID
        var ids = roleTemplateIds.Distinct().ToArray();
        if (ids.Length == 0)
        {
            return new Dictionary<long, IReadOnlyList<RoleTemplatePermission>>();
        }

        // 2. 批量查询权限
        var permissions = await dbContext.RoleTemplatePermissions.AsNoTracking()
            .Where(x => ids.Contains(x.RoleTemplateId))
            .ToListAsync(cancellationToken);

        // 3. 组装字典
        return permissions
            .GroupBy(x => x.RoleTemplateId)
            .ToDictionary(g => g.Key, g => (IReadOnlyList<RoleTemplatePermission>)g.ToList());
    }

    /// <summary>
    /// 新增角色模板并配置权限。
    /// </summary>
    /// <param name="template">角色模板实体。</param>
    /// <param name="permissionCodes">权限编码集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public async Task AddAsync(RoleTemplate template, IEnumerable<string> permissionCodes, CancellationToken cancellationToken = default)
    {
        // 1. 规范化模板字段
        template.TemplateCode = template.TemplateCode.Trim();
        template.Name = template.Name.Trim();
        // 2. 保存模板
        await dbContext.RoleTemplates.AddAsync(template, cancellationToken);
        // 3. 替换权限
        await ReplacePermissionsInternalAsync(template, permissionCodes, cancellationToken);
    }

    /// <summary>
    /// 更新角色模板并重置权限。
    /// </summary>
    /// <param name="template">角色模板实体。</param>
    /// <param name="permissionCodes">权限编码集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public async Task UpdateAsync(RoleTemplate template, IEnumerable<string> permissionCodes, CancellationToken cancellationToken = default)
    {
        // 1. 规范化模板字段
        template.TemplateCode = template.TemplateCode.Trim();
        template.Name = template.Name.Trim();
        // 2. 更新模板
        dbContext.RoleTemplates.Update(template);
        // 3. 重置权限
        await ReplacePermissionsInternalAsync(template, permissionCodes, cancellationToken);
    }

    /// <summary>
    /// 删除角色模板及其权限。
    /// </summary>
    /// <param name="roleTemplateId">模板 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public async Task DeleteAsync(long roleTemplateId, CancellationToken cancellationToken = default)
    {
        // 1. 查询模板
        var entity = await dbContext.RoleTemplates.FirstOrDefaultAsync(x => x.Id == roleTemplateId, cancellationToken);
        if (entity != null)
        {
            // 2. 删除关联权限
            var permissions = dbContext.RoleTemplatePermissions.Where(x => x.RoleTemplateId == roleTemplateId);
            dbContext.RoleTemplatePermissions.RemoveRange(permissions);
            // 3. 删除模板
            dbContext.RoleTemplates.Remove(entity);
        }
    }

    /// <summary>
    /// 保存仓储变更。
    /// </summary>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>保存任务。</returns>
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => dbContext.SaveChangesAsync(cancellationToken);

    private async Task ReplacePermissionsInternalAsync(RoleTemplate template, IEnumerable<string> permissionCodes, CancellationToken cancellationToken)
    {
        // 1. 使用执行策略保证一致性
        var strategy = dbContext.Database.CreateExecutionStrategy();
        await strategy.ExecuteAsync(async () =>
        {
            await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken);

            // 1. 确保模板已持久化，便于 FK 正确填充
            if (!dbContext.Entry(template).IsKeySet || template.Id == 0)
            {
                await dbContext.SaveChangesAsync(cancellationToken);
            }

            // 2. 归一化权限编码
            var normalized = permissionCodes
                .Where(code => !string.IsNullOrWhiteSpace(code))
                .Select(code => code.Trim())
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToArray();

            // 3. 清空旧权限（原生 SQL 避免跟踪干扰）
            await dbContext.Database.ExecuteSqlRawAsync(
                "DELETE FROM \"role_template_permissions\" WHERE \"RoleTemplateId\" = {0};",
                parameters: new object[] { template.Id },
                cancellationToken: cancellationToken);

            // 4. 插入新权限（ON CONFLICT DO NOTHING 防御重复）
            foreach (var code in normalized)
            {
                await dbContext.Database.ExecuteSqlRawAsync(
                    "INSERT INTO \"role_template_permissions\" (\"RoleTemplateId\",\"PermissionCode\",\"CreatedAt\",\"CreatedBy\",\"UpdatedAt\",\"UpdatedBy\",\"DeletedAt\",\"DeletedBy\") VALUES ({0},{1},NOW(),NULL,NULL,NULL,NULL,NULL) ON CONFLICT DO NOTHING;",
                    parameters: new object[] { template.Id, code },
                    cancellationToken: cancellationToken);
            }

            await trx.CommitAsync(cancellationToken);
        });
    }
}
