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

namespace AxCopilot.Handlers;

/// <summary>
/// L13-2: PATH 환경변수 뷰어·검색 핸들러. "path" 프리픽스로 사용합니다.
///
/// 예: path                   → PATH 전체 목록 (존재/미존재 여부 표시)
///     path search git        → "git" 포함 경로 필터
///     path which git.exe     → 실행 파일 위치 검색 (which/where 대응)
///     path which python      → 확장자 없이도 검색 (.exe/.cmd/.bat 시도)
///     path user              → 사용자 PATH만 표시
///     path system            → 시스템 PATH만 표시
/// Enter → 경로를 클립보드에 복사.
/// </summary>
public class PathHandler : IActionHandler
{
    public string? Prefix => "path";

    public PluginMetadata Metadata => new(
        "Path",
        "PATH 환경변수 뷰어 — 경로 목록 · 검색 · which",
        "1.0",
        "AX");

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q     = query.Trim();
        var items = new List<LauncherItem>();

        if (string.IsNullOrWhiteSpace(q))
        {
            var paths = GetAllPaths();
            var exist = paths.Count(p => p.Exists);
            var total = paths.Count;

            items.Add(new LauncherItem(
                $"PATH  {total}개 경로 (존재 {exist}개)",
                "path which <파일> 로 실행 파일 위치 검색",
                null, null, Symbol: "\uE838"));

            items.Add(new LauncherItem("path user",        "사용자 PATH만",    null, null, Symbol: "\uE838"));
            items.Add(new LauncherItem("path system",      "시스템 PATH만",    null, null, Symbol: "\uE838"));
            items.Add(new LauncherItem("path which git",   "git 위치 검색",    null, null, Symbol: "\uE838"));

            foreach (var p in paths.Take(15))
                items.Add(MakePathItem(p));

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

        var parts = q.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
        var sub   = parts[0].ToLowerInvariant();

        switch (sub)
        {
            case "which":
            case "where":
            case "find":
            {
                var target = parts.Length > 1 ? parts[1].Trim() : "";
                if (string.IsNullOrWhiteSpace(target))
                {
                    items.Add(new LauncherItem("파일명 입력", "예: path which git.exe", null, null, Symbol: "\uE783"));
                    break;
                }
                items.AddRange(FindExecutable(target));
                break;
            }

            case "user":
            {
                var paths = GetPaths(EnvironmentVariableTarget.User);
                items.Add(new LauncherItem($"사용자 PATH  {paths.Count}개", "", null, null, Symbol: "\uE838"));
                foreach (var p in paths)
                    items.Add(MakePathItem(p));
                break;
            }

            case "system":
            {
                var paths = GetPaths(EnvironmentVariableTarget.Machine);
                items.Add(new LauncherItem($"시스템 PATH  {paths.Count}개", "", null, null, Symbol: "\uE838"));
                foreach (var p in paths)
                    items.Add(MakePathItem(p));
                break;
            }

            case "search":
            {
                var keyword = parts.Length > 1 ? parts[1].ToLowerInvariant() : "";
                if (string.IsNullOrWhiteSpace(keyword))
                {
                    items.Add(new LauncherItem("검색어 입력", "예: path search python", null, null, Symbol: "\uE783"));
                    break;
                }
                var allPaths = GetAllPaths();
                var filtered = allPaths.Where(p =>
                    p.Directory.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count == 0)
                    items.Add(new LauncherItem("결과 없음", $"'{keyword}' 포함 경로 없음", null, null, Symbol: "\uE946"));
                else
                    foreach (var p in filtered)
                        items.Add(MakePathItem(p));
                break;
            }

            default:
            {
                // 기본: 검색어로 처리
                var keyword = q.ToLowerInvariant();
                var allPaths = GetAllPaths();
                var filtered = allPaths.Where(p =>
                    p.Directory.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count > 0)
                    foreach (var p in filtered.Take(15))
                        items.Add(MakePathItem(p));
                else
                    // which 로 재시도
                    items.AddRange(FindExecutable(q));
                break;
            }
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("copy", string text))
        {
            try
            {
                System.Windows.Application.Current.Dispatcher.Invoke(
                    () => Clipboard.SetText(text));
                NotificationService.Notify("Path", "클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
        }
        return Task.CompletedTask;
    }

    // ── PATH 수집 ─────────────────────────────────────────────────────────────

    private record PathEntry(string Directory, bool Exists, EnvironmentVariableTarget Scope);

    private static List<PathEntry> GetAllPaths()
    {
        var result = new List<PathEntry>();
        result.AddRange(GetPaths(EnvironmentVariableTarget.Process));
        return result.DistinctBy(p => p.Directory.ToLowerInvariant()).ToList();
    }

    private static List<PathEntry> GetPaths(EnvironmentVariableTarget target)
    {
        var raw = Environment.GetEnvironmentVariable("PATH", target) ?? "";
        return raw.Split(';', StringSplitOptions.RemoveEmptyEntries)
                  .Where(p => !string.IsNullOrWhiteSpace(p))
                  .Select(p => new PathEntry(p.Trim(), Directory.Exists(p.Trim()), target))
                  .ToList();
    }

    private static IEnumerable<LauncherItem> FindExecutable(string name)
    {
        var extensions = new[] { "", ".exe", ".cmd", ".bat", ".ps1", ".com" };
        var paths      = GetAllPaths();
        var found      = new List<string>();

        foreach (var pathEntry in paths.Where(p => p.Exists))
        {
            foreach (var ext in extensions)
            {
                var candidate = Path.Combine(pathEntry.Directory, name + ext);
                if (File.Exists(candidate))
                    found.Add(candidate);
            }
        }

        if (found.Count == 0)
        {
            yield return new LauncherItem($"'{name}' 찾을 수 없음",
                "PATH에서 해당 실행 파일이 없습니다", null, null, Symbol: "\uE946");
            yield break;
        }

        yield return new LauncherItem(
            $"'{name}'  {found.Count}개 발견",
            "전체 복사: Enter",
            null, ("copy", string.Join("\n", found)), Symbol: "\uE838");

        foreach (var f in found)
        {
            var dir      = Path.GetDirectoryName(f) ?? "";
            var fileName = Path.GetFileName(f);
            yield return new LauncherItem(
                fileName,
                dir,
                null, ("copy", f), Symbol: "\uE838");
        }
    }

    private static LauncherItem MakePathItem(PathEntry p)
    {
        var icon  = p.Exists ? "\uE838" : "\uE783";
        var label = p.Exists ? "" : " (없는 경로)";
        return new LauncherItem(
            p.Directory + label,
            p.Exists ? "존재함" : "경로 없음",
            null,
            ("copy", p.Directory),
            Symbol: icon);
    }
}
