using System.Collections.Concurrent;
using System.IO;
using System.Net.Http;
using System.Windows.Media.Imaging;

namespace AxCopilot.Services;

/// <summary>
/// 외부 URL의 favicon을 다운로드하여 캐시합니다.
/// Google Favicon API (https://www.google.com/s2/favicons?domain=xxx&sz=32)를 사용합니다.
/// 캐시는 메모리(ConcurrentDictionary) + 디스크(%APPDATA%\AxCopilot\favicons\)에 저장됩니다.
/// </summary>
public static class FaviconService
{
    private static readonly string CacheDir = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
        "AxCopilot", "favicons");

    private static readonly ConcurrentDictionary<string, BitmapImage?> _memCache = new();
    private static readonly HttpClient _http = new() { Timeout = TimeSpan.FromSeconds(5) };

    /// <summary>
    /// 도메인의 favicon BitmapImage를 반환합니다.
    /// 캐시에 있으면 즉시 반환, 없으면 null 반환 후 백그라운드에서 다운로드합니다.
    /// 다운로드 완료 시 콜백을 호출합니다.
    /// </summary>
    public static BitmapImage? GetFavicon(string url, Action? onLoaded = null)
    {
        var domain = ExtractDomain(url);
        if (string.IsNullOrEmpty(domain)) return null;

        // 메모리 캐시 확인
        if (_memCache.TryGetValue(domain, out var cached))
            return cached;

        // 디스크 캐시 확인
        var diskPath = Path.Combine(CacheDir, $"{domain}.png");
        if (File.Exists(diskPath))
        {
            try
            {
                var bmp = LoadFromDisk(diskPath);
                _memCache[domain] = bmp;
                return bmp;
            }
            catch (Exception) { }
        }

        // 백그라운드에서 다운로드
        _memCache[domain] = null; // 중복 요청 방지
        _ = DownloadAsync(domain, diskPath, onLoaded);
        return null;
    }

    private static async Task DownloadAsync(string domain, string diskPath, Action? onLoaded)
    {
        try
        {
            var faviconUrl = $"https://www.google.com/s2/favicons?domain={Uri.EscapeDataString(domain)}&sz=32";
            var bytes = await _http.GetByteArrayAsync(faviconUrl).ConfigureAwait(false);

            if (bytes.Length < 100) return; // 너무 작으면 유효한 이미지 아님

            // 디스크 저장
            Directory.CreateDirectory(CacheDir);
            await File.WriteAllBytesAsync(diskPath, bytes).ConfigureAwait(false);

            // 메모리 캐시 갱신
            System.Windows.Application.Current?.Dispatcher.Invoke(() =>
            {
                try
                {
                    var bmp = LoadFromDisk(diskPath);
                    _memCache[domain] = bmp;
                    onLoaded?.Invoke();
                }
                catch (Exception) { }
            });
        }
        catch (Exception ex)
        {
            LogService.Warn($"Favicon 다운로드 실패: {domain} — {ex.Message}");
        }
    }

    private static BitmapImage LoadFromDisk(string path)
    {
        var bmp = new BitmapImage();
        bmp.BeginInit();
        bmp.UriSource = new Uri(path, UriKind.Absolute);
        bmp.CacheOption = BitmapCacheOption.OnLoad;
        bmp.DecodePixelWidth = 32;
        bmp.EndInit();
        bmp.Freeze();
        return bmp;
    }

    private static string? ExtractDomain(string url)
    {
        try
        {
            if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                url = "https://" + url;
            return new Uri(url).Host.ToLowerInvariant();
        }
        catch (Exception) { return null; }
    }
}
