using Microsoft.EntityFrameworkCore;
using DramaLing.Api.Data;
using DramaLing.Api.Models.Entities;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

namespace DramaLing.Api.Services;

public interface IAnalysisCacheService
{
    Task<SentenceAnalysisCache?> GetCachedAnalysisAsync(string inputText);
    Task<string> SetCachedAnalysisAsync(string inputText, object analysisResult, TimeSpan ttl);
    Task<bool> InvalidateCacheAsync(string textHash);
    Task<int> GetCacheHitCountAsync();
    Task CleanExpiredCacheAsync();
}

public class AnalysisCacheService : IAnalysisCacheService
{
    private readonly DramaLingDbContext _context;
    private readonly ILogger<AnalysisCacheService> _logger;

    public AnalysisCacheService(DramaLingDbContext context, ILogger<AnalysisCacheService> logger)
    {
        _context = context;
        _logger = logger;
    }

    /// <summary>
    /// 獲取快取的分析結果
    /// </summary>
    public async Task<SentenceAnalysisCache?> GetCachedAnalysisAsync(string inputText)
    {
        try
        {
            var textHash = GenerateTextHash(inputText);
            var cached = await _context.SentenceAnalysisCache
                .FirstOrDefaultAsync(c => c.InputTextHash == textHash && c.ExpiresAt > DateTime.UtcNow);

            if (cached != null)
            {
                // 更新訪問統計
                cached.AccessCount++;
                cached.LastAccessedAt = DateTime.UtcNow;
                await _context.SaveChangesAsync();

                _logger.LogInformation("Cache hit for text hash: {TextHash}", textHash);
                return cached;
            }

            _logger.LogInformation("Cache miss for text hash: {TextHash}", textHash);
            return null;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting cached analysis for text: {InputText}", inputText);
            return null;
        }
    }

    /// <summary>
    /// 設定快取分析結果
    /// </summary>
    public async Task<string> SetCachedAnalysisAsync(string inputText, object analysisResult, TimeSpan ttl)
    {
        try
        {
            var textHash = GenerateTextHash(inputText);
            var expiresAt = DateTime.UtcNow.Add(ttl);

            // 檢查是否已存在
            var existing = await _context.SentenceAnalysisCache
                .FirstOrDefaultAsync(c => c.InputTextHash == textHash);

            if (existing != null)
            {
                // 更新現有快取 - 使用一致的命名策略
                var options = new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                };
                existing.AnalysisResult = JsonSerializer.Serialize(analysisResult, options);
                existing.ExpiresAt = expiresAt;
                existing.AccessCount++;
                existing.LastAccessedAt = DateTime.UtcNow;
            }
            else
            {
                // 創建新快取項目
                var cacheItem = new SentenceAnalysisCache
                {
                    Id = Guid.NewGuid(),
                    InputTextHash = textHash,
                    InputText = inputText,
                    AnalysisResult = JsonSerializer.Serialize(analysisResult, new JsonSerializerOptions
                    {
                        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                    }),
                    CreatedAt = DateTime.UtcNow,
                    ExpiresAt = expiresAt,
                    AccessCount = 1,
                    LastAccessedAt = DateTime.UtcNow
                };

                _context.SentenceAnalysisCache.Add(cacheItem);
            }

            await _context.SaveChangesAsync();

            _logger.LogInformation("Cached analysis for text hash: {TextHash}, expires at: {ExpiresAt}",
                textHash, expiresAt);

            return textHash;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error setting cached analysis for text: {InputText}", inputText);
            throw;
        }
    }

    /// <summary>
    /// 使快取失效
    /// </summary>
    public async Task<bool> InvalidateCacheAsync(string textHash)
    {
        try
        {
            var cached = await _context.SentenceAnalysisCache
                .FirstOrDefaultAsync(c => c.InputTextHash == textHash);

            if (cached != null)
            {
                _context.SentenceAnalysisCache.Remove(cached);
                await _context.SaveChangesAsync();

                _logger.LogInformation("Invalidated cache for text hash: {TextHash}", textHash);
                return true;
            }

            return false;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error invalidating cache for text hash: {TextHash}", textHash);
            return false;
        }
    }

    /// <summary>
    /// 獲取快取命中次數
    /// </summary>
    public async Task<int> GetCacheHitCountAsync()
    {
        try
        {
            return await _context.SentenceAnalysisCache
                .Where(c => c.ExpiresAt > DateTime.UtcNow)
                .SumAsync(c => c.AccessCount);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error getting cache hit count");
            return 0;
        }
    }

    /// <summary>
    /// 清理過期的快取
    /// </summary>
    public async Task CleanExpiredCacheAsync()
    {
        try
        {
            var expiredItems = await _context.SentenceAnalysisCache
                .Where(c => c.ExpiresAt <= DateTime.UtcNow)
                .ToListAsync();

            if (expiredItems.Any())
            {
                _context.SentenceAnalysisCache.RemoveRange(expiredItems);
                await _context.SaveChangesAsync();

                _logger.LogInformation("Cleaned {Count} expired cache items", expiredItems.Count);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error cleaning expired cache");
        }
    }

    /// <summary>
    /// 生成文本哈希值
    /// </summary>
    private string GenerateTextHash(string inputText)
    {
        using var sha256 = SHA256.Create();
        var bytes = Encoding.UTF8.GetBytes(inputText.Trim().ToLower());
        var hash = sha256.ComputeHash(bytes);
        return Convert.ToHexString(hash).ToLower();
    }
}