using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.Metrics;

namespace TakeoutSaaS.Infrastructure.Dictionary.Caching;

/// <summary>
/// 缓存命中/耗时指标采集器。
/// </summary>
public sealed class CacheMetricsCollector
{
    private const string MeterName = "TakeoutSaaS.DictionaryCache";
    private static readonly Meter Meter = new(MeterName, "1.0.0");

    private readonly Counter<long> _hitCounter;
    private readonly Counter<long> _missCounter;
    private readonly Counter<long> _invalidationCounter;
    private readonly Histogram<double> _durationHistogram;
    private readonly ConcurrentQueue<CacheQueryRecord> _queries = new();
    private readonly TimeSpan _retention = TimeSpan.FromDays(7);

    private long _hitTotal;
    private long _missTotal;

    /// <summary>
    /// 初始化指标采集器。
    /// </summary>
    public CacheMetricsCollector()
    {
        _hitCounter = Meter.CreateCounter<long>("cache_hit_count");
        _missCounter = Meter.CreateCounter<long>("cache_miss_count");
        _invalidationCounter = Meter.CreateCounter<long>("cache_invalidation_count");
        _durationHistogram = Meter.CreateHistogram<double>("cache_query_duration_ms");

        Meter.CreateObservableGauge(
            "cache_hit_ratio",
            () => new Measurement<double>(CalculateHitRatio()));
    }

    /// <summary>
    /// 记录缓存命中。
    /// </summary>
    public void RecordHit(string cacheLevel, string dictionaryCode)
    {
        Interlocked.Increment(ref _hitTotal);
        _hitCounter.Add(1, new TagList
        {
            { "cache_level", cacheLevel },
            { "dictionary_code", NormalizeCode(dictionaryCode) }
        });
    }

    /// <summary>
    /// 记录缓存未命中。
    /// </summary>
    public void RecordMiss(string cacheLevel, string dictionaryCode)
    {
        Interlocked.Increment(ref _missTotal);
        _missCounter.Add(1, new TagList
        {
            { "cache_level", cacheLevel },
            { "dictionary_code", NormalizeCode(dictionaryCode) }
        });
    }

    /// <summary>
    /// 记录缓存查询耗时。
    /// </summary>
    public void RecordDuration(string dictionaryCode, double durationMs)
    {
        _durationHistogram.Record(durationMs, new TagList
        {
            { "dictionary_code", NormalizeCode(dictionaryCode) }
        });
    }

    /// <summary>
    /// 记录查询详情，用于统计窗口分析。
    /// </summary>
    public void RecordQuery(string dictionaryCode, bool l1Hit, bool l2Hit, double durationMs)
    {
        var record = new CacheQueryRecord(DateTime.UtcNow, NormalizeCode(dictionaryCode), l1Hit, l2Hit, durationMs);
        _queries.Enqueue(record);
        PruneOldRecords();
    }

    /// <summary>
    /// 记录缓存失效事件。
    /// </summary>
    public void RecordInvalidation(string dictionaryCode)
    {
        _invalidationCounter.Add(1, new TagList
        {
            { "dictionary_code", NormalizeCode(dictionaryCode) }
        });
    }

    /// <summary>
    /// 获取指定时间范围内的统计快照。
    /// </summary>
    public CacheStatsSnapshot GetSnapshot(TimeSpan window)
    {
        var since = DateTime.UtcNow.Subtract(window);
        var records = _queries.Where(record => record.Timestamp >= since).ToList();

        var l1Hits = records.Count(record => record.L1Hit);
        var l1Misses = records.Count(record => !record.L1Hit);
        var l2Hits = records.Count(record => record.L2Hit);
        var l2Misses = records.Count(record => !record.L1Hit && !record.L2Hit);

        var totalHits = l1Hits + l2Hits;
        var totalMisses = l1Misses + l2Misses;
        var hitRatio = totalHits + totalMisses == 0 ? 0 : totalHits / (double)(totalHits + totalMisses);
        var averageDuration = records.Count == 0 ? 0 : records.Average(record => record.DurationMs);

        var topQueried = records
            .GroupBy(record => record.DictionaryCode)
            .Select(group => new DictionaryQueryCount(group.Key, group.Count()))
            .OrderByDescending(item => item.QueryCount)
            .Take(5)
            .ToList();

        return new CacheStatsSnapshot(
            totalHits,
            totalMisses,
            hitRatio,
            new CacheLevelStats(l1Hits, l2Hits),
            new CacheLevelStats(l1Misses, l2Misses),
            averageDuration,
            topQueried);
    }

    /// <summary>
    /// 从缓存键解析字典编码。
    /// </summary>
    public static string ExtractDictionaryCode(string cacheKey)
    {
        if (string.IsNullOrWhiteSpace(cacheKey))
        {
            return "unknown";
        }

        if (cacheKey.StartsWith("dict:groups:", StringComparison.Ordinal))
        {
            return "groups";
        }

        if (cacheKey.StartsWith("dict:items:", StringComparison.Ordinal))
        {
            return "items";
        }

        if (cacheKey.StartsWith("dict:", StringComparison.Ordinal))
        {
            var parts = cacheKey.Split(':', StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length >= 3)
            {
                return parts[2];
            }
        }

        return "unknown";
    }

    private static string NormalizeCode(string? code)
        => string.IsNullOrWhiteSpace(code) ? "unknown" : code.Trim().ToLowerInvariant();

    private double CalculateHitRatio()
    {
        var hits = Interlocked.Read(ref _hitTotal);
        var misses = Interlocked.Read(ref _missTotal);
        return hits + misses == 0 ? 0 : hits / (double)(hits + misses);
    }

    private void PruneOldRecords()
    {
        var cutoff = DateTime.UtcNow.Subtract(_retention);
        while (_queries.TryPeek(out var record) && record.Timestamp < cutoff)
        {
            _queries.TryDequeue(out _);
        }
    }

    private sealed record CacheQueryRecord(
        DateTime Timestamp,
        string DictionaryCode,
        bool L1Hit,
        bool L2Hit,
        double DurationMs);
}

/// <summary>
/// 缓存统计快照。
/// </summary>
public sealed record CacheStatsSnapshot(
    long TotalHits,
    long TotalMisses,
    double HitRatio,
    CacheLevelStats HitsByLevel,
    CacheLevelStats MissesByLevel,
    double AverageQueryDurationMs,
    IReadOnlyList<DictionaryQueryCount> TopQueriedDictionaries);

/// <summary>
/// 命中统计。
/// </summary>
public sealed record CacheLevelStats(long L1, long L2);

/// <summary>
/// 字典查询次数统计。
/// </summary>
public sealed record DictionaryQueryCount(string Code, int QueryCount);
