using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Text;
using Microsoft.Extensions.Caching.Memory;
using Nalu.Web.Models;

namespace Nalu.Web.Services;

public class CacheService
{
    private readonly IMemoryCache _cache;
    private readonly IConfiguration _config;

    // Per-validator version counter — bumped when the validator file changes.
    // Including the version in the cache key effectively invalidates all cached
    // responses for that validator without needing to enumerate cache entries.
    private readonly ConcurrentDictionary<string, int> _versions = new();

    public CacheService(IMemoryCache cache, IConfiguration config)
    {
        _cache = cache;
        _config = config;
    }

    /// <summary>Called by ValidatorLoader when a validator file changes on disk.</summary>
    public void InvalidateValidator(string validatorId)
    {
        _versions.AddOrUpdate(validatorId, 1, (_, v) => v + 1);
    }

    public bool TryGet(string validatorId, ExtractionRequest request, out ExtractionResponse? response)
    {
        var key = ComputeKey(validatorId, request);
        return _cache.TryGetValue(key, out response);
    }

    public void Set(string validatorId, ExtractionRequest request, ExtractionResponse response)
    {
        var ttl = _config.GetValue<int>("Cache:DefaultTtlMinutes", 60);
        var key = ComputeKey(validatorId, request);
        _cache.Set(key, response, TimeSpan.FromMinutes(ttl));
    }

    private string ComputeKey(string validatorId, ExtractionRequest request)
    {
        var version = _versions.GetValueOrDefault(validatorId, 0);
        var raw = $"{validatorId}|v{version}|{request.AgentInput}|{request.UserInput}|{request.AgentContext}|{request.Language}";
        var hash = SHA256.HashData(Encoding.UTF8.GetBytes(raw));
        return Convert.ToHexString(hash);
    }
}
