using Meezi.Core.Interfaces;
using Meezi.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;

namespace Meezi.Infrastructure.Services;

public class PlatformRuntimeConfig : IPlatformRuntimeConfig
{
    private const string CacheKey = "platform:settings:all";
    private readonly AppDbContext _db;
    private readonly IConfiguration _configuration;
    private readonly IMemoryCache _cache;

    public PlatformRuntimeConfig(
        AppDbContext db,
        IConfiguration configuration,
        IMemoryCache cache)
    {
        _db = db;
        _configuration = configuration;
        _cache = cache;
    }

    public void InvalidateCache() => _cache.Remove(CacheKey);

    public async Task<string?> GetAsync(string key, CancellationToken cancellationToken = default)
    {
        var map = await LoadMapAsync(cancellationToken);
        if (map.TryGetValue(key, out var v) && !string.IsNullOrWhiteSpace(v))
            return v;
        return _configuration[key.Replace('.', ':')];
    }

    public async Task<IReadOnlyDictionary<string, string>> GetByPrefixAsync(
        string prefix,
        CancellationToken cancellationToken = default)
    {
        var map = await LoadMapAsync(cancellationToken);
        return map
            .Where(kv => kv.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
            .ToDictionary(kv => kv.Key, kv => kv.Value, StringComparer.OrdinalIgnoreCase);
    }

    private async Task<Dictionary<string, string>> LoadMapAsync(CancellationToken cancellationToken)
    {
        return await _cache.GetOrCreateAsync(CacheKey, async entry =>
        {
            entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(2);
            var rows = await _db.PlatformSettings.AsNoTracking()
                .Select(s => new { s.Key, s.Value })
                .ToListAsync(cancellationToken);
            return rows.ToDictionary(r => r.Key, r => r.Value, StringComparer.OrdinalIgnoreCase);
        }) ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }
}
