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

namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;

/// <summary>
/// 字典分组仓储实现。
/// </summary>
public sealed class DictionaryGroupRepository(DictionaryDbContext context) : IDictionaryGroupRepository
{
    private static readonly Func<DictionaryDbContext, long, DictionaryCode, Task<DictionaryGroup?>> GetByCodeQuery =
        EF.CompileAsyncQuery((DictionaryDbContext db, long tenantId, DictionaryCode code) =>
            db.DictionaryGroups
                .AsNoTracking()
                .FirstOrDefault(group => group.TenantId == tenantId && group.DeletedAt == null && group.Code == code));

    /// <summary>
    /// 按 ID 获取字典分组。
    /// </summary>
    public Task<DictionaryGroup?> GetByIdAsync(long groupId, CancellationToken cancellationToken = default)
    {
        return context.DictionaryGroups
            .AsNoTracking()
            .FirstOrDefaultAsync(group => group.Id == groupId && group.DeletedAt == null, cancellationToken);
    }

    /// <summary>
    /// 按编码获取字典分组。
    /// </summary>
    public Task<DictionaryGroup?> GetByCodeAsync(long tenantId, DictionaryCode code, CancellationToken cancellationToken = default)
    {
        _ = cancellationToken;
        return GetByCodeQuery(context, tenantId, code);
    }

    /// <summary>
    /// 分页获取字典分组。
    /// </summary>
    public async Task<IReadOnlyList<DictionaryGroup>> GetPagedAsync(
        long tenantId,
        DictionaryScope? scope,
        string? keyword,
        bool? isEnabled,
        int page,
        int pageSize,
        string? sortBy,
        bool sortDescending,
        CancellationToken cancellationToken = default)
    {
        var query = BuildQuery(tenantId, scope, keyword, isEnabled);

        var skip = Math.Max(page - 1, 0) * Math.Max(pageSize, 1);
        query = ApplyOrdering(query, sortBy, sortDescending);

        return await query
            .Skip(skip)
            .Take(pageSize)
            .ToListAsync(cancellationToken);
    }

    /// <summary>
    /// 获取满足条件的分组数量。
    /// </summary>
    public Task<int> CountAsync(
        long tenantId,
        DictionaryScope? scope,
        string? keyword,
        bool? isEnabled,
        CancellationToken cancellationToken = default)
    {
        return BuildQuery(tenantId, scope, keyword, isEnabled)
            .CountAsync(cancellationToken);
    }

    /// <summary>
    /// 批量获取字典分组。
    /// </summary>
    public async Task<IReadOnlyList<DictionaryGroup>> GetByIdsAsync(IEnumerable<long> groupIds, CancellationToken cancellationToken = default)
    {
        var ids = groupIds?.Distinct().ToArray() ?? Array.Empty<long>();
        if (ids.Length == 0)
        {
            return Array.Empty<DictionaryGroup>();
        }

        return await context.DictionaryGroups
            .AsNoTracking()
            .Where(group => ids.Contains(group.Id) && group.DeletedAt == null)
            .ToListAsync(cancellationToken);
    }

    private static IQueryable<DictionaryGroup> ApplyOrdering(IQueryable<DictionaryGroup> query, string? sortBy, bool sortDescending)
    {
        var normalized = sortBy?.Trim().ToLowerInvariant();
        return normalized switch
        {
            "name" => sortDescending ? query.OrderByDescending(group => group.Name) : query.OrderBy(group => group.Name),
            "createdat" => sortDescending ? query.OrderByDescending(group => group.CreatedAt) : query.OrderBy(group => group.CreatedAt),
            "updatedat" => sortDescending ? query.OrderByDescending(group => group.UpdatedAt) : query.OrderBy(group => group.UpdatedAt),
            _ => sortDescending ? query.OrderByDescending(group => group.Code) : query.OrderBy(group => group.Code)
        };
    }

    /// <summary>
    /// 新增分组。
    /// </summary>
    public Task AddAsync(DictionaryGroup group, CancellationToken cancellationToken = default)
    {
        context.DictionaryGroups.Add(group);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 更新分组。
    /// </summary>
    public Task UpdateAsync(DictionaryGroup group, CancellationToken cancellationToken = default)
    {
        context.DictionaryGroups.Update(group);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除分组。
    /// </summary>
    public Task RemoveAsync(DictionaryGroup group, CancellationToken cancellationToken = default)
    {
        context.DictionaryGroups.Remove(group);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 持久化更改。
    /// </summary>
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
        => context.SaveChangesAsync(cancellationToken);

    private IQueryable<DictionaryGroup> BuildQuery(long tenantId, DictionaryScope? scope, string? keyword, bool? isEnabled)
    {
        var query = context.DictionaryGroups
            .AsNoTracking()
            .Where(group => group.TenantId == tenantId && group.DeletedAt == null);

        if (scope.HasValue)
        {
            query = query.Where(group => group.Scope == scope.Value);
        }

        if (!string.IsNullOrWhiteSpace(keyword))
        {
            var trimmed = keyword.Trim();
            if (DictionaryCode.IsValid(trimmed))
            {
                var code = new DictionaryCode(trimmed);
                query = query.Where(group => group.Code == code || group.Name.Contains(trimmed));
            }
            else
            {
                query = query.Where(group => group.Name.Contains(trimmed));
            }
        }

        if (isEnabled.HasValue)
        {
            query = query.Where(group => group.IsEnabled == isEnabled.Value);
        }

        return query;
    }
}
