using Microsoft.Win32;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L14-2: Windows 레지스트리 빠른 조회 핸들러. "reg" 프리픽스로 사용합니다.
///
/// 예: reg HKCU\Software\Microsoft     → 키 하위 값 목록
///     reg HKLM\SOFTWARE\Microsoft     → HKLM 조회
///     reg search DisplayName          → 값 이름으로 검색 (제한적)
///     reg HKCU\...\Run                → 실행 항목 조회
/// Enter → 값을 클립보드에 복사.
///
/// 쓰기/삭제 기능 없음 — 조회 전용.
/// </summary>
public class RegHandler : IActionHandler
{
    public string? Prefix => "reg";

    public PluginMetadata Metadata => new(
        "Reg",
        "레지스트리 조회 — HKCU · HKLM 키·값 빠른 조회",
        "1.0",
        "AX");

    // 자주 쓰는 즐겨찾기 경로
    private static readonly (string Label, string Path)[] Favorites =
    [
        ("현재 사용자 Run",          @"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"),
        ("모든 사용자 Run",           @"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"),
        ("설치된 프로그램 (32bit)",   @"HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"),
        ("설치된 프로그램 (64bit)",   @"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"),
        ("환경 변수 (사용자)",        @"HKCU\Environment"),
        ("환경 변수 (시스템)",        @"HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"),
        ("Internet Explorer 설정",   @"HKCU\SOFTWARE\Microsoft\Internet Explorer\Main"),
        ("Windows 테마",             @"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes"),
        ("탐색기 설정",               @"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced"),
    ];

    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("레지스트리 조회",
                "예: reg HKCU\\Software\\Microsoft  /  reg HKLM\\SOFTWARE\\...",
                null, null, Symbol: "\uE8BE"));
            items.Add(new LauncherItem("── 즐겨찾기 ──", "", null, null, Symbol: "\uE8BE"));
            foreach (var (label, path) in Favorites)
                items.Add(new LauncherItem(label, path, null, ("query", path), Symbol: "\uE8BE"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

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

        if (sub == "search" || sub == "find")
        {
            var keyword = parts.Length > 1 ? parts[1] : "";
            if (string.IsNullOrWhiteSpace(keyword))
            {
                items.Add(new LauncherItem("검색어 입력", "예: reg search DisplayName", null, null, Symbol: "\uE783"));
            }
            else
            {
                // 즐겨찾기 경로에서 해당 이름 검색
                items.Add(new LauncherItem($"'{keyword}' 즐겨찾기에서 검색", "일치하는 경로:", null, null, Symbol: "\uE8BE"));
                foreach (var (label, path) in Favorites.Where(f =>
                    f.Label.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
                    f.Path.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
                {
                    items.Add(new LauncherItem(label, path, null, ("query", path), Symbol: "\uE8BE"));
                }
            }
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 레지스트리 경로 조회
        var regPath = q;
        items.AddRange(QueryRegistry(regPath));
        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("Reg", "클립보드에 복사했습니다.");
                }
                catch { /* 비핵심 */ }
                break;

            case ("query", string path):
                // 이미 GetItemsAsync에서 처리됨 — 재조회용 트리거 (런처 재갱신 불가 시 알림만)
                NotificationService.Notify("Reg", $"조회: {path.Split('\\').Last()}");
                break;
        }
        return Task.CompletedTask;
    }

    // ── 레지스트리 조회 ──────────────────────────────────────────────────────

    private static IEnumerable<LauncherItem> QueryRegistry(string path)
    {
        var (hive, subKey) = SplitPath(path);
        if (hive == null)
        {
            yield return new LauncherItem("형식 오류",
                "HKCU 또는 HKLM으로 시작하는 경로를 입력하세요", null, null, Symbol: "\uE783");
            yield break;
        }

        RegistryKey? key = null;
        string? openError = null;
        try { key = hive.OpenSubKey(subKey, writable: false); }
        catch (Exception ex) { openError = ex.Message; }

        if (openError != null)
        {
            yield return new LauncherItem("접근 오류", openError, null, null, Symbol: "\uE783");
            yield break;
        }

        if (key == null)
        {
            yield return new LauncherItem("키 없음", $"'{path}' 키가 존재하지 않습니다", null, null, Symbol: "\uE946");
            yield break;
        }

        using (key)
        {
            // 하위 키 목록
            var subKeys = key.GetSubKeyNames();
            if (subKeys.Length > 0)
            {
                yield return new LauncherItem($"하위 키  {subKeys.Length}개", path, null, null, Symbol: "\uE8BE");
                foreach (var sk in subKeys.Take(10))
                {
                    var fullPath = path.TrimEnd('\\') + @"\" + sk;
                    yield return new LauncherItem($"[{sk}]", fullPath, null, ("copy", fullPath), Symbol: "\uE8BE");
                }
            }

            // 값 목록
            var valueNames = key.GetValueNames();
            if (valueNames.Length > 0)
            {
                yield return new LauncherItem($"── 값  {valueNames.Length}개 ──", "", null, null, Symbol: "\uE8BE");
                foreach (var vn in valueNames.Take(20))
                {
                    var val     = key.GetValue(vn);
                    var valStr  = FormatValue(val);
                    var display = string.IsNullOrEmpty(vn) ? "(기본값)" : vn;
                    yield return new LauncherItem(
                        display,
                        valStr.Length > 80 ? valStr[..80] + "…" : valStr,
                        null, ("copy", valStr), Symbol: "\uE8BE");
                }
            }

            if (subKeys.Length == 0 && valueNames.Length == 0)
                yield return new LauncherItem("빈 키", "하위 키와 값이 없습니다", null, null, Symbol: "\uE946");
        }
    }

    private static (RegistryKey? Hive, string SubKey) SplitPath(string path)
    {
        path = path.Replace('/', '\\');
        var sep = path.IndexOf('\\');
        var hiveStr = sep >= 0 ? path[..sep].ToUpperInvariant() : path.ToUpperInvariant();
        var sub     = sep >= 0 ? path[(sep + 1)..] : "";

        var hive = hiveStr switch
        {
            "HKCU" or "HKEY_CURRENT_USER"   => Registry.CurrentUser,
            "HKLM" or "HKEY_LOCAL_MACHINE"  => Registry.LocalMachine,
            "HKCR" or "HKEY_CLASSES_ROOT"   => Registry.ClassesRoot,
            "HKU"  or "HKEY_USERS"          => Registry.Users,
            "HKCC" or "HKEY_CURRENT_CONFIG" => Registry.CurrentConfig,
            _ => null,
        };
        return (hive, sub);
    }

    private static string FormatValue(object? val) => val switch
    {
        null          => "(null)",
        string s      => s,
        int i         => $"{i}  (0x{i:X8})",
        long l        => $"{l}  (0x{l:X16})",
        byte[] bytes  => BitConverter.ToString(bytes).Replace("-", " "),
        string[] arr  => string.Join(" | ", arr),
        _             => val.ToString() ?? "",
    };
}
