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

namespace AxCopilot.Handlers;

/// <summary>
/// L21-3: PowerShell 명령 생성기 핸들러. "ps" 프리픽스로 사용합니다.
///
/// 예: ps                     → 카테고리별 자주 쓰는 명령 목록
///     ps <키워드>            → 명령 검색 (예: ps process, ps service, ps file)
///     ps file                → 파일/디렉토리 명령 목록
///     ps process             → 프로세스 명령 목록
///     ps network             → 네트워크 명령 목록
///     ps service             → 서비스 명령 목록
///     ps registry            → 레지스트리 명령 목록
///     ps string              → 문자열 처리 명령 목록
///     ps date                → 날짜/시간 명령 목록
///     ps pipe                → 파이프라인 예시
///     ps run <명령>          → 직접 PowerShell 실행
/// Enter → 클립보드 복사 (또는 PS 터미널 실행).
/// </summary>
public class PsHandler : IActionHandler
{
    public string? Prefix => "ps";

    public PluginMetadata Metadata => new(
        "PS",
        "PowerShell 명령 생성기 — 파일·프로세스·네트워크·서비스·레지스트리",
        "1.0",
        "AX");

    private record PsCmd(string Cmd, string Description, string Category);

    private static readonly PsCmd[] Commands =
    [
        // 파일/디렉토리
        new("Get-ChildItem -Path . -Recurse",                          "현재 폴더 재귀 목록",                          "file"),
        new("Get-ChildItem -Filter *.log -Recurse",                    "*.log 파일 재귀 검색",                         "file"),
        new("Copy-Item src.txt dst.txt",                               "파일 복사",                                    "file"),
        new("Move-Item src.txt dst.txt",                               "파일 이동/이름변경",                           "file"),
        new("Remove-Item -Path file.txt -Force",                       "파일 강제 삭제",                               "file"),
        new("New-Item -ItemType Directory -Path .\\NewFolder",         "새 폴더 생성",                                 "file"),
        new("Get-Content file.txt",                                    "파일 내용 출력",                               "file"),
        new("Get-Content file.txt -Tail 20",                           "파일 마지막 20줄 (tail)",                      "file"),
        new("Set-Content file.txt \"내용\"",                           "파일 쓰기",                                    "file"),
        new("Add-Content file.txt \"추가 내용\"",                      "파일에 내용 추가",                             "file"),
        new("Test-Path C:\\path\\to\\file",                            "경로 존재 여부 확인",                          "file"),
        new("Resolve-Path .\\relative\\path",                          "상대 경로 → 절대 경로",                        "file"),
        new("Get-Item file.txt | Select-Object Length,LastWriteTime",  "파일 크기·수정일 조회",                        "file"),
        new("(Get-ChildItem -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB", "폴더 크기 계산 (MB)", "file"),
        new("Compress-Archive -Path .\\folder -DestinationPath out.zip","폴더 압축 (.zip)",                           "file"),
        new("Expand-Archive -Path file.zip -DestinationPath .\\out",   "zip 압축 해제",                               "file"),

        // 프로세스
        new("Get-Process",                                             "실행 중인 프로세스 목록",                      "process"),
        new("Get-Process -Name chrome | Sort-Object CPU -Desc",        "Chrome 프로세스 CPU 순 정렬",                  "process"),
        new("Stop-Process -Name notepad -Force",                       "notepad 강제 종료",                            "process"),
        new("Stop-Process -Id 1234 -Force",                            "PID로 프로세스 종료",                          "process"),
        new("Start-Process chrome.exe",                                "프로세스 실행",                                "process"),
        new("Start-Process notepad -Verb RunAs",                       "관리자 권한으로 실행",                         "process"),
        new("Get-Process | Where-Object {$_.CPU -gt 10} | Sort-Object CPU -Desc | Select -First 5", "CPU 10% 이상 상위 5개", "process"),
        new("Get-WmiObject Win32_Process | Select-Object Name,ProcessId,CommandLine", "프로세스 명령줄 조회", "process"),
        new("(Get-Process -Id $PID).Path",                             "현재 PowerShell 실행 경로",                   "process"),

        // 서비스
        new("Get-Service",                                             "모든 서비스 목록",                             "service"),
        new("Get-Service | Where-Object {$_.Status -eq 'Running'}",    "실행 중인 서비스만",                           "service"),
        new("Start-Service -Name wuauserv",                            "Windows Update 서비스 시작",                   "service"),
        new("Stop-Service -Name wuauserv",                             "서비스 중지",                                  "service"),
        new("Restart-Service -Name Spooler",                           "인쇄 스풀러 재시작",                           "service"),
        new("Set-Service -Name Fax -StartupType Disabled",             "서비스 시작 유형 변경 (비활성화)",             "service"),
        new("Get-Service -Name sshd",                                  "SSH 서비스 상태 확인",                         "service"),

        // 네트워크
        new("Test-NetConnection google.com -Port 443",                 "도메인+포트 연결 테스트",                      "network"),
        new("Test-NetConnection 8.8.8.8",                              "IP ping 테스트",                               "network"),
        new("Get-NetIPAddress -AddressFamily IPv4",                    "IPv4 주소 목록",                               "network"),
        new("Get-NetAdapter | Where-Object {$_.Status -eq 'Up'}",      "활성 네트워크 어댑터 목록",                    "network"),
        new("Get-NetTCPConnection -State Listen",                      "Listen 상태 포트 목록",                        "network"),
        new("Get-NetTCPConnection | Where-Object {$_.LocalPort -eq 80}","포트 80 연결 조회",                          "network"),
        new("Resolve-DnsName google.com",                              "DNS 조회",                                     "network"),
        new("(Invoke-WebRequest -Uri 'https://api.ipify.org').Content", "공인 IP 주소 확인",                          "network"),
        new("Invoke-WebRequest -Uri 'http://localhost:8080/health'",   "HTTP GET 요청",                                "network"),

        // 레지스트리
        new("Get-ItemProperty HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", "시작 프로그램 확인", "registry"),
        new("Get-ChildItem HKLM:\\SOFTWARE",                           "HKLM\\SOFTWARE 하위 키 목록",                  "registry"),
        new("New-ItemProperty -Path HKCU:\\Software -Name MyVal -Value 1 -PropertyType DWORD", "레지스트리 값 쓰기", "registry"),
        new("Remove-ItemProperty -Path HKCU:\\Software -Name MyVal",  "레지스트리 값 삭제",                           "registry"),

        // 문자열·데이터
        new("\"hello world\" -replace 'world','PowerShell'",          "문자열 치환",                                  "string"),
        new("\"  text  \".Trim()",                                     "문자열 앞뒤 공백 제거",                        "string"),
        new("[System.Web.HttpUtility]::UrlEncode('hello world')",     "URL 인코딩",                                   "string"),
        new("[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes('hello'))", "Base64 인코딩",                  "string"),
        new("[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('aGVsbG8='))", "Base64 디코딩",            "string"),
        new("Get-FileHash file.txt -Algorithm SHA256",                 "파일 SHA256 해시",                             "string"),
        new("$text | ConvertTo-Json",                                  "객체 → JSON 변환",                             "string"),
        new("Get-Content file.json | ConvertFrom-Json",               "JSON 파일 파싱",                               "string"),
        new("Import-Csv data.csv",                                     "CSV 파일 파싱",                                "string"),
        new("Export-Csv -Path out.csv -NoTypeInformation",            "CSV 파일 내보내기",                            "string"),

        // 날짜/시간
        new("Get-Date",                                                "현재 날짜·시간",                               "date"),
        new("Get-Date -Format 'yyyy-MM-dd HH:mm:ss'",                 "날짜 포맷 지정",                               "date"),
        new("(Get-Date).AddDays(30)",                                  "30일 후 날짜",                                 "date"),
        new("(Get-Date) - (Get-Date '2024-01-01')",                   "날짜 차이 계산",                               "date"),
        new("[datetime]::UtcNow",                                      "UTC 현재 시각",                                "date"),
        new("[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()",           "Unix 타임스탬프 (초)",                         "date"),
        new("[DateTimeOffset]::FromUnixTimeSeconds(1700000000).LocalDateTime", "Unix 타임스탬프 → 날짜",            "date"),

        // 파이프라인
        new("Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 | Format-Table", "상위 10 프로세스 테이블 출력", "pipe"),
        new("Get-ChildItem *.txt | ForEach-Object { $_.Name }",       "txt 파일 이름만 추출",                         "pipe"),
        new("1..10 | ForEach-Object { $_ * $_ }",                     "1~10 제곱수 생성",                             "pipe"),
        new("'a','b','c' | Where-Object { $_ -ne 'b' }",              "배열 필터링",                                  "pipe"),
        new("Get-Content log.txt | Select-String 'ERROR'",            "파일에서 ERROR 줄 검색",                       "pipe"),
        new("Get-EventLog -LogName System -Newest 50 | Where-Object {$_.EntryType -eq 'Error'}", "시스템 이벤트 오류 조회", "pipe"),
    ];

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

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("PowerShell 명령 생성기",
                "ps file · process · network · service · registry · string · date · pipe · run <명령>",
                null, null, Symbol: "\uE756"));
            AddCategoryOverview(items);
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        // ps run <명령>
        if (sub == "run" && parts.Length >= 2)
        {
            var cmd = parts[1];
            items.Add(new LauncherItem(cmd, "Enter → PowerShell에서 실행",
                null, ("run", cmd), Symbol: "\uE756"));
            items.Add(new LauncherItem("클립보드 복사", cmd, null, ("copy", cmd), Symbol: "\uE756"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 카테고리 조회
        var catMatch = Commands.Where(c => c.Category.Equals(sub, StringComparison.OrdinalIgnoreCase)).ToList();
        if (catMatch.Count > 0)
        {
            var catName = sub switch
            {
                "file"     => "파일/디렉토리",
                "process"  => "프로세스",
                "service"  => "서비스",
                "network"  => "네트워크",
                "registry" => "레지스트리",
                "string"   => "문자열·데이터",
                "date"     => "날짜/시간",
                "pipe"     => "파이프라인 예시",
                _          => sub
            };
            items.Add(new LauncherItem($"── {catName} ──", $"{catMatch.Count}개 명령", null, null, Symbol: "\uE756"));
            foreach (var c in catMatch)
                items.Add(new LauncherItem(TruncateStr(c.Cmd, 70), c.Description,
                    null, ("copy", c.Cmd), Symbol: "\uE756"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 키워드 검색
        var keyword = string.Join(" ", parts);
        var found   = Commands.Where(c =>
            c.Cmd.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
            c.Description.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

        if (found.Count > 0)
        {
            items.Add(new LauncherItem($"'{keyword}' 검색 결과: {found.Count}개", "", null, null, Symbol: "\uE756"));
            foreach (var c in found)
                items.Add(new LauncherItem(TruncateStr(c.Cmd, 70), c.Description,
                    null, ("copy", c.Cmd), Symbol: "\uE756"));
        }
        else
        {
            items.Add(new LauncherItem($"'{keyword}' 결과 없음",
                "ps file · process · network · service · registry · string · date · pipe",
                null, null, Symbol: "\uE783"));
            AddCategoryOverview(items);
        }

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        switch (item.Data)
        {
            case ("copy", string text):
                try
                {
                    System.Windows.Application.Current.Dispatcher.Invoke(
                        () => Clipboard.SetText(text));
                    NotificationService.Notify("PS", "클립보드에 복사했습니다.");
                }
                catch { }
                break;

            case ("run", string cmd):
                RunInPowerShell(cmd);
                break;
        }
        return Task.CompletedTask;
    }

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

    private static void AddCategoryOverview(List<LauncherItem> items)
    {
        var cats = new (string Key, string Label)[]
        {
            ("file",     "파일/디렉토리  — Get-ChildItem · Copy-Item · Remove-Item · Compress-Archive"),
            ("process",  "프로세스       — Get-Process · Stop-Process · Start-Process"),
            ("service",  "서비스         — Get-Service · Start-Service · Stop-Service"),
            ("network",  "네트워크       — Test-NetConnection · Get-NetIPAddress · Resolve-DnsName"),
            ("registry", "레지스트리     — Get-ItemProperty · New-ItemProperty · Remove-ItemProperty"),
            ("string",   "문자열·데이터  — ConvertTo-Json · Get-FileHash · Import-Csv"),
            ("date",     "날짜/시간      — Get-Date · AddDays · UnixTimeSeconds"),
            ("pipe",     "파이프라인     — Sort-Object · Where-Object · ForEach-Object"),
        };
        foreach (var (key, label) in cats)
            items.Add(new LauncherItem($"ps {key}", label, null, null, Symbol: "\uE756"));
    }

    private static void RunInPowerShell(string cmd)
    {
        try
        {
            // Windows Terminal 우선
            var wtPath = System.IO.Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                @"Microsoft\WindowsApps\wt.exe");
            if (System.IO.File.Exists(wtPath))
            {
                Process.Start(new ProcessStartInfo
                {
                    FileName  = wtPath,
                    Arguments = $"PowerShell -NoExit -Command \"{cmd.Replace("\"", "\\\"")}\"",
                    UseShellExecute = true
                });
                return;
            }
            Process.Start(new ProcessStartInfo
            {
                FileName  = "powershell.exe",
                Arguments = $"-NoExit -Command \"{cmd.Replace("\"", "\\\"")}\"",
                UseShellExecute = true
            });
        }
        catch { }
    }

    private static string TruncateStr(string s, int max) =>
        s.Length <= max ? s : s[..max] + "…";
}
