using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Dictionary.Entities;
using TakeoutSaaS.Domain.Dictionary.Enums;
using TakeoutSaaS.Domain.Dictionary.Repositories;
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;

namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;

/// <summary>
/// EF Core 字典仓储实现。
/// </summary>
public sealed class EfDictionaryRepository(DictionaryDbContext context) : IDictionaryRepository
{
    /// <summary>
    /// 根据分组 ID 查询分组。
    /// </summary>
    /// <param name="id">分组 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>匹配分组或 null。</returns>
    public Task<DictionaryGroup?> FindGroupByIdAsync(long id, CancellationToken cancellationToken = default)
        => context.DictionaryGroups.FirstOrDefaultAsync(group => group.Id == id, cancellationToken);

    /// <summary>
    /// 根据分组编码查询分组。
    /// </summary>
    /// <param name="code">分组编码。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>匹配分组或 null。</returns>
    public Task<DictionaryGroup?> FindGroupByCodeAsync(string code, CancellationToken cancellationToken = default)
        => context.DictionaryGroups.FirstOrDefaultAsync(group => group.Code == code, cancellationToken);

    /// <summary>
    /// 搜索分组列表。
    /// </summary>
    /// <param name="scope">字典作用域。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>分组列表。</returns>
    public async Task<IReadOnlyList<DictionaryGroup>> SearchGroupsAsync(DictionaryScope? scope, CancellationToken cancellationToken = default)
    {
        // 1. 构建分组查询
        var query = context.DictionaryGroups.AsNoTracking();
        if (scope.HasValue)
        {
            // 2. 按作用域过滤
            query = query.Where(group => group.Scope == scope.Value);
        }

        // 3. 排序返回
        return await query
            .OrderBy(group => group.Code)
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// 新增分组。
    /// </summary>
    /// <param name="group">分组实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task AddGroupAsync(DictionaryGroup group, CancellationToken cancellationToken = default)
    {
        // 1. 添加分组
        context.DictionaryGroups.Add(group);
        // 2. 返回完成任务
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除分组。
    /// </summary>
    /// <param name="group">分组实体。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task RemoveGroupAsync(DictionaryGroup group, CancellationToken cancellationToken = default)
    {
        // 1. 移除分组
        context.DictionaryGroups.Remove(group);
        // 2. 返回完成任务
        return Task.CompletedTask;
    }

    /// <summary>
    /// 根据条目 ID 查询字典项。
    /// </summary>
    /// <param name="id">条目 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>匹配条目或 null。</returns>
    public Task<DictionaryItem?> FindItemByIdAsync(long id, CancellationToken cancellationToken = default)
        => context.DictionaryItems.FirstOrDefaultAsync(item => item.Id == id, cancellationToken);

    /// <summary>
    /// 获取指定分组下的条目列表。
    /// </summary>
    /// <param name="groupId">分组 ID。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>条目列表。</returns>
    public async Task<IReadOnlyList<DictionaryItem>> GetItemsByGroupIdAsync(long groupId, CancellationToken cancellationToken = default)
    {
        // 1. 过滤分组
        return await context.DictionaryItems
            .AsNoTracking()
            .Where(item => item.GroupId == groupId)
            .OrderBy(item => item.SortOrder)
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// 新增字典项。
    /// </summary>
    /// <param name="item">字典项。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task AddItemAsync(DictionaryItem item, CancellationToken cancellationToken = default)
    {
        // 1. 添加条目
        context.DictionaryItems.Add(item);
        // 2. 返回完成任务
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除字典项。
    /// </summary>
    /// <param name="item">字典项。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task RemoveItemAsync(DictionaryItem item, CancellationToken cancellationToken = default)
    {
        // 1. 移除条目
        context.DictionaryItems.Remove(item);
        // 2. 返回完成任务
        return Task.CompletedTask;
    }

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

    /// <summary>
    /// 根据编码集合获取条目列表，可包含系统级条目。
    /// </summary>
    /// <param name="codes">分组编码集合。</param>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="includeSystem">是否包含系统级。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>条目列表。</returns>
    public async Task<IReadOnlyList<DictionaryItem>> GetItemsByCodesAsync(IEnumerable<string> codes, long tenantId, bool includeSystem, CancellationToken cancellationToken = default)
    {
        // 1. 规范化编码
        var normalizedCodes = codes
            .Where(code => !string.IsNullOrWhiteSpace(code))
            .Select(code => code.Trim().ToLowerInvariant())
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToArray();

        if (normalizedCodes.Length == 0)
        {
            return Array.Empty<DictionaryItem>();
        }

        // 2. 构建查询并忽略 QueryFilter
        var query = context.DictionaryItems
            .AsNoTracking()
            .IgnoreQueryFilters()
            .Include(item => item.Group)
            .Where(item => normalizedCodes.Contains(item.Group!.Code));

        // 3. 按租户或系统级过滤
        query = query.Where(item => item.TenantId == tenantId || (includeSystem && item.TenantId == 0));

        // 4. 排序返回
        return await query
            .OrderBy(item => item.SortOrder)
            .ToListAsync(cancellationToken);
    }
}
