using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using System.Text.Json;
using TakeoutSaaS.Application.Dictionary.Abstractions;
using TakeoutSaaS.Application.Dictionary.Models;
using TakeoutSaaS.Infrastructure.Dictionary.Options;

namespace TakeoutSaaS.Infrastructure.Dictionary.Services;

/// <summary>
/// 基于 IDistributedCache 的字典缓存实现。
/// </summary>
public sealed class DistributedDictionaryCache(IDistributedCache cache, IOptions<DictionaryCacheOptions> options) : IDictionaryCache
{
    private readonly DictionaryCacheOptions _options = options.Value;
    private readonly JsonSerializerOptions _serializerOptions = new(JsonSerializerDefaults.Web);

    /// <summary>
    /// 读取指定租户与编码的字典缓存。
    /// </summary>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="code">字典编码。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>字典项集合或 null。</returns>
    public async Task<IReadOnlyList<DictionaryItemDto>?> GetAsync(long tenantId, string code, CancellationToken cancellationToken = default)
    {
        // 1. 拼装缓存键
        var cacheKey = BuildKey(tenantId, code);
        var payload = await cache.GetAsync(cacheKey, cancellationToken);
        if (payload == null || payload.Length == 0)
        {
            return null;
        }

        // 2. 反序列化
        return JsonSerializer.Deserialize<List<DictionaryItemDto>>(payload, _serializerOptions);
    }

    /// <summary>
    /// 设置指定租户与编码的字典缓存。
    /// </summary>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="code">字典编码。</param>
    /// <param name="items">字典项集合。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task SetAsync(long tenantId, string code, IReadOnlyList<DictionaryItemDto> items, CancellationToken cancellationToken = default)
    {
        // 1. 序列化并写入缓存
        var cacheKey = BuildKey(tenantId, code);
        var payload = JsonSerializer.SerializeToUtf8Bytes(items, _serializerOptions);
        var options = new DistributedCacheEntryOptions
        {
            SlidingExpiration = _options.SlidingExpiration
        };
        return cache.SetAsync(cacheKey, payload, options, cancellationToken);
    }

    /// <summary>
    /// 移除指定租户与编码的缓存。
    /// </summary>
    /// <param name="tenantId">租户 ID。</param>
    /// <param name="code">字典编码。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>异步任务。</returns>
    public Task RemoveAsync(long tenantId, string code, CancellationToken cancellationToken = default)
    {
        // 1. 删除缓存键
        var cacheKey = BuildKey(tenantId, code);
        return cache.RemoveAsync(cacheKey, cancellationToken);
    }

    private static string BuildKey(long tenantId, string code)
        => $"dictionary:{tenantId}:{code.ToLowerInvariant()}";
}
