using System.Security.Cryptography;
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Dictionary.Entities;
using TakeoutSaaS.Domain.Dictionary.Repositories;
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;

/// <summary>
/// 字典项仓储实现。
/// </summary>
public sealed class DictionaryItemRepository(DictionaryDbContext context, ITenantContextAccessor tenantContextAccessor) : IDictionaryItemRepository
{
    private static readonly Func<DictionaryDbContext, long, long, IEnumerable<DictionaryItem>> GetByGroupQuery =
        EF.CompileQuery((DictionaryDbContext db, long tenantId, long groupId) =>
            (IEnumerable<DictionaryItem>)db.DictionaryItems
                .AsNoTracking()
                .Where(item => item.GroupId == groupId && item.TenantId == tenantId && item.DeletedAt == null)
                .OrderBy(item => item.SortOrder));

    /// <summary>
    /// 根据 ID 获取字典项。
    /// </summary>
    public Task<DictionaryItem?> GetByIdAsync(long itemId, CancellationToken cancellationToken = default)
    {
        return context.DictionaryItems
            .AsNoTracking()
            .FirstOrDefaultAsync(item => item.Id == itemId && item.DeletedAt == null, cancellationToken);
    }

    /// <summary>
    /// 获取分组下字典项列表。
    /// </summary>
    public Task<IReadOnlyList<DictionaryItem>> GetByGroupIdAsync(
        long tenantId,
        long groupId,
        CancellationToken cancellationToken = default)
    {
        _ = cancellationToken;
        return Task.FromResult<IReadOnlyList<DictionaryItem>>(
            GetByGroupQuery(context, tenantId, groupId).ToList());
    }

    /// <summary>
    /// 获取系统与租户合并的字典项列表。
    /// </summary>
    public async Task<IReadOnlyList<DictionaryItem>> GetMergedItemsAsync(
        long tenantId,
        long systemGroupId,
        bool includeOverrides,
        CancellationToken cancellationToken = default)
    {
        DictionaryGroup? systemGroup;
        List<DictionaryItem> systemItems;
        using (tenantContextAccessor.EnterTenantScope(0, "dictionary"))
        {
            systemGroup = await context.DictionaryGroups
                .AsNoTracking()
                .FirstOrDefaultAsync(group => group.Id == systemGroupId && group.DeletedAt == null, cancellationToken);
            if (systemGroup == null)
            {
                return Array.Empty<DictionaryItem>();
            }

            systemItems = await context.DictionaryItems
                .AsNoTracking()
                .Where(item => item.GroupId == systemGroupId && item.DeletedAt == null)
                .OrderBy(item => item.SortOrder)
                .ToListAsync(cancellationToken);
        }

        var result = new List<DictionaryItem>(systemItems);

        if (!includeOverrides || tenantId == 0)
        {
            return result;
        }

        var tenantGroup = await context.DictionaryGroups
            .AsNoTracking()
            .FirstOrDefaultAsync(group =>
                group.TenantId == tenantId &&
                group.DeletedAt == null &&
                group.Code == systemGroup.Code,
                cancellationToken);

        if (tenantGroup == null)
        {
            return result;
        }

        var tenantItems = await context.DictionaryItems
            .AsNoTracking()
            .Where(item => item.GroupId == tenantGroup.Id && item.TenantId == tenantId && item.DeletedAt == null)
            .OrderBy(item => item.SortOrder)
            .ToListAsync(cancellationToken);

        result.AddRange(tenantItems);
        return result;
    }

    /// <summary>
    /// 新增字典项。
    /// </summary>
    public Task AddAsync(DictionaryItem item, CancellationToken cancellationToken = default)
    {
        context.DictionaryItems.Add(item);
        return Task.CompletedTask;
    }

    /// <summary>
    /// 更新字典项。
    /// </summary>
    public Task UpdateAsync(DictionaryItem item, CancellationToken cancellationToken = default)
    {
        var entry = context.Entry(item);
        if (entry.State == EntityState.Detached)
        {
            context.DictionaryItems.Attach(item);
            entry = context.Entry(item);
        }

        entry.State = EntityState.Modified;
        var originalVersion = item.RowVersion;
        var nextVersion = RandomNumberGenerator.GetBytes(16);
        entry.Property(x => x.RowVersion).OriginalValue = originalVersion;
        entry.Property(x => x.RowVersion).CurrentValue = nextVersion;
        item.RowVersion = nextVersion;
        return Task.CompletedTask;
    }

    /// <summary>
    /// 删除字典项。
    /// </summary>
    public Task RemoveAsync(DictionaryItem item, CancellationToken cancellationToken = default)
    {
        context.DictionaryItems.Remove(item);
        return Task.CompletedTask;
    }

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