using System.IO;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 웹 검색 핸들러. "?" 예약어로 사용합니다.
/// 예: ? 오늘 날씨           → 기본 검색엔진으로 검색
///     ? github.com          → URL 직접 열기
///     ?g 파이썬 튜토리얼     → Google 검색
///     ?n naver 뉴스          → Naver 검색
///     ?y youtube 음악        → YouTube 검색
///     ?g github.com          → GitHub 직접
/// </summary>
public class WebSearchHandler : IActionHandler
{
    private readonly SettingsService _settings;

    /// <summary>내장 검색 엔진 아이콘 폴더 (Assets\SearchEngines)</summary>
    private static readonly string _iconDir = Path.Combine(
        Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) ?? ".",
        "Assets", "SearchEngines");

    public WebSearchHandler(SettingsService settings) => _settings = settings;

    public string? Prefix => "?";

    public PluginMetadata Metadata => new(
        "WebSearch",
        "웹 검색 — ? 뒤에 검색어 또는 URL 입력",
        "1.0",
        "AX");

    // 검색 엔진 단축 접두어 — Icon: 내장 PNG 파일명 (확장자 제외)
    private static readonly Dictionary<string, (string Name, string UrlTemplate, string Icon)> _engines = new()
    {
        ["g"]  = ("Google",        "https://www.google.com/search?q={0}",                            "google"),
        ["n"]  = ("Naver",         "https://search.naver.com/search.naver?query={0}",                "naver"),
        ["y"]  = ("YouTube",       "https://www.youtube.com/results?search_query={0}",               "youtube"),
        ["gh"] = ("GitHub",        "https://github.com/search?q={0}",                                "github"),
        ["d"]  = ("DuckDuckGo",    "https://duckduckgo.com/?q={0}",                                  "duckduckgo"),
        ["w"]  = ("Wikipedia",     "https://ko.wikipedia.org/w/index.php?search={0}",                "wikipedia"),
        ["nm"] = ("Naver Map",     "https://map.naver.com/p/search/{0}",                              "navermap"),
        ["nw"] = ("나무위키",      "https://namu.wiki/Special:Search?query={0}",                      "namuwiki"),
        ["ni"] = ("Naver 이미지",  "https://search.naver.com/search.naver?where=image&query={0}",    "naver"),
        ["gi"] = ("Google 이미지", "https://www.google.com/search?tbm=isch&q={0}",                   "google"),
    };

    /// <summary>엔진 키에 대응하는 내장 아이콘 파일 경로를 반환합니다. 없으면 null.</summary>
    private static string? GetIconPath(string engineKey)
    {
        if (!_engines.TryGetValue(engineKey, out var eng)) return null;
        var path = Path.Combine(_iconDir, $"{eng.Icon}.png");
        return File.Exists(path) ? path : null;
    }

    private string DefaultEngineKey =>
        _settings.Settings.Launcher.WebSearchEngine ?? "g";

    private (string Name, string UrlTemplate, string Icon) DefaultEngine =>
        _engines.TryGetValue(DefaultEngineKey, out var eng) ? eng : _engines["g"];

    private const string SecurityWarn = "⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지";

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        // 사내 모드에서는 웹 검색 차단
        if (_settings.Settings.InternalModeEnabled)
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    "웹 검색 차단됨",
                    "사내 모드에서는 외부 인터넷 검색이 차단됩니다. 설정에서 사외 모드를 활성화하세요.",
                    null, null, Symbol: Symbols.Lock)
            ]);
        }

        if (string.IsNullOrWhiteSpace(query))
        {
            var defIcon = GetIconPath(DefaultEngineKey);
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    "검색어를 입력하세요",
                    $"예: ? 오늘 날씨  ·  ?g python  ·  ?y 음악  ·  ?n 뉴스  |  {SecurityWarn}",
                    defIcon, null, Symbol: Symbols.Globe)
            ]);
        }

        var items = new List<LauncherItem>();
        var q = query.Trim();

        // URL인 경우 직접 열기 — FaviconService로 웹에서 아이콘 가져오기
        if (IsUrl(q))
        {
            var url = q.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? q : "https://" + q;
            var faviconPath = GetFaviconPathForUrl(url);
            items.Add(new LauncherItem(
                $"열기: {q}",
                $"{url}  |  {SecurityWarn}",
                faviconPath, url, Symbol: Symbols.Globe));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 엔진 단축어 확인 (예: "g 파이썬" → Google 검색)
        var parts = q.Split(' ', 2);
        var engineKey = parts[0].ToLowerInvariant();
        if (parts.Length == 2 && _engines.TryGetValue(engineKey, out var engine))
        {
            var searchQuery = parts[1].Trim();
            if (!string.IsNullOrWhiteSpace(searchQuery))
            {
                var url = string.Format(engine.UrlTemplate, Uri.EscapeDataString(searchQuery));
                items.Add(new LauncherItem(
                    $"{engine.Name}에서 '{searchQuery}' 검색",
                    $"{SecurityWarn}",
                    GetIconPath(engineKey), url, Symbol: Symbols.Globe));
            }
        }

        // 기본 엔진 검색 항목
        var defKey = DefaultEngineKey;
        var def = DefaultEngine;
        var defaultUrl = string.Format(def.UrlTemplate, Uri.EscapeDataString(q));
        items.Add(new LauncherItem(
            $"{def.Name}에서 '{q}' 검색",
            SecurityWarn,
            GetIconPath(defKey), defaultUrl, Symbol: Symbols.Globe));

        // 빠른 접속 사이트 표시 (쿼리가 짧을 때만)
        if (q.Length <= 2)
        {
            foreach (var (key, eng) in _engines)
            {
                items.Add(new LauncherItem(
                    $"?{key} — {eng.Name}",
                    $"예: ?{key} {q}  |  {SecurityWarn}",
                    GetIconPath(key), null, Symbol: Symbols.Globe));
            }
        }

        return Task.FromResult<IEnumerable<LauncherItem>>(items);
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        // 사내 모드에서는 실행도 차단
        if (_settings.Settings.InternalModeEnabled) return Task.CompletedTask;

        if (item.Data is string url && !string.IsNullOrWhiteSpace(url))
        {
            try
            {
                System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(url)
                    { UseShellExecute = true });
            }
            catch (Exception ex)
            {
                LogService.Warn($"웹 검색 열기 실패: {ex.Message}");
            }
        }
        return Task.CompletedTask;
    }

    // ─── URL 판별 ────────────────────────────────────────────────────────────

    private static bool IsUrl(string input)
    {
        if (input.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
            input.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            return true;

        // xxx.yyy 형태 (도메인처럼 보이는 경우)
        if (!input.Contains(' ') && input.Contains('.') && input.Length > 3)
        {
            var domainPart = input.Split('/')[0];
            var tldPart    = domainPart.Split('.');
            return tldPart.Length >= 2
                && tldPart[^1].Length >= 2
                && tldPart[^1].Length <= 6
                && tldPart[^1].All(char.IsLetter);
        }

        return false;
    }

    // ─── URL 파비콘 가져오기 (FaviconService 연동) ─────────────────────────

    /// <summary>
    /// URL에 대한 파비콘 경로를 반환합니다.
    /// FaviconService 디스크 캐시에 있으면 즉시 반환, 없으면 백그라운드 다운로드를 시작합니다.
    /// </summary>
    private static string? GetFaviconPathForUrl(string url)
    {
        try
        {
            if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
                url = "https://" + url;
            var domain = new Uri(url).Host.ToLowerInvariant();
            var cachePath = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                "AxCopilot", "favicons", $"{domain}.png");

            if (File.Exists(cachePath))
                return cachePath;

            // 디스크 캐시에 없으면 FaviconService를 통해 백그라운드 다운로드 시작
            FaviconService.GetFavicon(url);
            return null;
        }
        catch (Exception) { return null; }
    }
}
