using System.Diagnostics;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;

namespace AxCopilot.Handlers;

/// <summary>
/// L22-1: 프로세스 상세 조회·정리 핸들러. "proc" 프리픽스로 사용합니다.
///
/// 예: proc                  → CPU 사용량 상위 프로세스 목록
///     proc top              → CPU 상위 15개
///     proc mem              → 메모리 상위 15개
///     proc <이름>           → 이름 검색 (부분 일치)
///     proc kill <이름>      → 이름으로 종료 (첫 번째 일치)
///     proc stats            → 전체 통계 (수·CPU합·메모리합)
/// Enter → 프로세스 이름 복사.
/// </summary>
public class ProcHandler : IActionHandler
{
    public string? Prefix => "proc";

    public PluginMetadata Metadata => new(
        "프로세스 관리",
        "실행 중인 프로세스 조회·정리 — CPU·메모리 정렬·검색·종료",
        "1.0",
        "AX");

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

        var parts = q.Split(' ', StringSplitOptions.RemoveEmptyEntries);
        var sub   = parts.Length > 0 ? parts[0].ToLowerInvariant() : "";

        // kill 서브커맨드
        if (sub is "kill" or "종료" or "stop")
        {
            if (parts.Length < 2)
            {
                items.Add(ErrorItem("예: proc kill <프로세스명>"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }
            var target = parts[1];
            var killed = KillProcess(target);
            items.Add(killed
                ? new LauncherItem($"✓ '{target}' 종료 완료", "프로세스가 종료되었습니다", null, null, Symbol: "\uE74D")
                : new LauncherItem($"'{target}' 프로세스를 찾을 수 없습니다", "실행 중인지 확인하세요", null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 프로세스 목록 수집
        Process[] procs;
        try { procs = Process.GetProcesses(); }
        catch (Exception ex)
        {
            items.Add(ErrorItem($"프로세스 조회 실패: {ex.Message}"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // stats
        if (sub is "stats" or "stat")
        {
            var totalMem = procs.Sum(p => SafeWorkingSet(p));
            var totalCpu = CountHighCpu(procs);
            items.Add(new LauncherItem("프로세스 통계", "", null, null, Symbol: "\uE9D9"));
            items.Add(CopyItem("전체 프로세스 수", procs.Length.ToString()));
            items.Add(CopyItem("전체 메모리 사용", FormatBytes(totalMem)));
            items.Add(CopyItem("CPU 10%+ 프로세스", $"{totalCpu}개"));
            items.Add(CopyItem("고유 프로세스 종류", procs.Select(p => p.ProcessName).Distinct().Count().ToString()));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 이름 검색
        if (!string.IsNullOrWhiteSpace(sub) && sub is not "top" and not "mem" and not "all")
        {
            var matched = procs
                .Where(p => p.ProcessName.Contains(sub, StringComparison.OrdinalIgnoreCase))
                .OrderByDescending(p => SafeWorkingSet(p))
                .Take(20)
                .ToList();

            if (matched.Count == 0)
            {
                items.Add(new LauncherItem($"'{sub}' 프로세스 없음", "실행 중인 프로세스를 검색합니다", null, null, Symbol: "\uE783"));
                return Task.FromResult<IEnumerable<LauncherItem>>(items);
            }

            items.Add(new LauncherItem($"'{sub}' 검색 결과 {matched.Count}개",
                "Enter: 이름 복사 · proc kill <이름>으로 종료", null, null, Symbol: "\uE721"));

            foreach (var p in matched)
                items.Add(BuildItem(p));

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

        // mem: 메모리 정렬
        if (sub is "mem" or "memory" or "메모리")
        {
            var top = procs.OrderByDescending(p => SafeWorkingSet(p)).Take(15).ToList();
            items.Add(new LauncherItem($"메모리 상위 {top.Count}개 프로세스",
                "메모리 사용량 내림차순", null, null, Symbol: "\uE9D9"));
            foreach (var p in top) items.Add(BuildItem(p));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // top / 기본: CPU 정렬 (WorkingSet 근사치 사용, CPU%는 샘플링 필요)
        {
            var top = procs
                .OrderByDescending(p => SafeWorkingSet(p))
                .Take(15)
                .ToList();

            var label = sub is "top" ? $"CPU/메모리 상위 {top.Count}개" : $"실행 중 프로세스 상위 {top.Count}개";
            items.Add(new LauncherItem(label,
                $"전체 {procs.Length}개 실행 중 · proc mem / proc <검색어> / proc kill <이름>",
                null, null, Symbol: "\uE9D9"));

            foreach (var p in top) items.Add(BuildItem(p));
        }

        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("프로세스", "클립보드에 복사했습니다.");
            }
            catch { }
        }
        return Task.CompletedTask;
    }

    // ── 헬퍼 ──────────────────────────────────────────────────────────────

    private static LauncherItem BuildItem(Process p)
    {
        var mem  = SafeWorkingSet(p);
        var name = p.ProcessName;
        var pid  = p.Id;
        var sub  = $"PID {pid}  ·  {FormatBytes(mem)}";
        return new LauncherItem(name, sub, null, ("copy", name), Symbol: "\uE9D9");
    }

    private static long SafeWorkingSet(Process p)
    {
        try { return p.WorkingSet64; }
        catch { return 0; }
    }

    private static int CountHighCpu(Process[] procs)
    {
        // CPU 퍼센트를 정확히 측정하려면 2회 샘플링이 필요하므로
        // 여기서는 스레드 수 > 5 를 기준으로 근사
        int count = 0;
        foreach (var p in procs)
        {
            try { if (p.Threads.Count > 5) count++; }
            catch { }
        }
        return count;
    }

    private static bool KillProcess(string name)
    {
        var targets = Process.GetProcessesByName(name);
        if (targets.Length == 0)
        {
            // 확장자 없이 시도
            var noExt = System.IO.Path.GetFileNameWithoutExtension(name);
            targets = Process.GetProcessesByName(noExt);
        }
        if (targets.Length == 0) return false;
        foreach (var p in targets)
        {
            try { p.Kill(); } catch { }
        }
        return true;
    }

    private static string FormatBytes(long bytes)
    {
        if (bytes >= 1_073_741_824) return $"{bytes / 1_073_741_824.0:F1} GB";
        if (bytes >= 1_048_576)     return $"{bytes / 1_048_576.0:F0} MB";
        if (bytes >= 1_024)         return $"{bytes / 1_024.0:F0} KB";
        return $"{bytes} B";
    }

    private static LauncherItem CopyItem(string label, string value) =>
        new(label, value, null, ("copy", value), Symbol: "\uE9D9");

    private static LauncherItem ErrorItem(string msg) =>
        new(msg, "올바른 입력 형식을 확인하세요", null, null, Symbol: "\uE783");
}
