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

namespace AxCopilot.Handlers;

/// <summary>
/// L12-4: 시작 프로그램 조회 핸들러. "startup" 프리픽스로 사용합니다.
///
/// 예: startup               → 전체 시작 프로그램 목록
///     startup search ms    → "ms" 포함 항목 필터
///     startup folder       → 시작 프로그램 폴더 열기
/// Enter → 항목 경로를 클립보드에 복사.
/// </summary>
public class StartupHandler : IActionHandler
{
    public string? Prefix => "startup";

    public PluginMetadata Metadata => new(
        "Startup",
        "시작 프로그램 조회 — 레지스트리 · 폴더 · 필터",
        "1.0",
        "AX");

    // 조회할 레지스트리 키 경로들
    private static readonly (string Path, string Scope)[] RegKeys =
    [
        (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",         "현재 사용자"),
        (@"SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",     "현재 사용자 (1회)"),
        (@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run", "현재 사용자 (32bit)"),
    ];

    private static readonly (string Path, string Scope)[] RegKeysHKLM =
    [
        (@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run",         "모든 사용자"),
        (@"SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",     "모든 사용자 (1회)"),
        (@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run", "모든 사용자 (32bit)"),
    ];

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

        var allEntries = CollectAllEntries();

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem(
                $"시작 프로그램  {allEntries.Count}개",
                "레지스트리 + 시작 폴더",
                null, null, Symbol: "\uE7FC"));

            items.Add(new LauncherItem("startup folder", "시작 폴더 열기", null, ("open_folder", ""), Symbol: "\uE7FC"));

            // 그룹별 표시
            var byScope = allEntries.GroupBy(e => e.Scope).OrderBy(g => g.Key);
            foreach (var group in byScope)
            {
                items.Add(new LauncherItem($"── {group.Key} ({group.Count()}개) ──", "", null, null, Symbol: "\uE7FC"));
                foreach (var e in group.Take(10))
                    items.Add(MakeEntryItem(e));
            }

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

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

        switch (sub)
        {
            case "folder":
            {
                items.Add(new LauncherItem("시작 폴더 열기 (현재 사용자)", GetStartupFolderUser(),
                    null, ("open_folder", GetStartupFolderUser()), Symbol: "\uE7FC"));
                items.Add(new LauncherItem("시작 폴더 열기 (모든 사용자)", GetStartupFolderCommon(),
                    null, ("open_folder", GetStartupFolderCommon()), Symbol: "\uE7FC"));
                break;
            }

            case "search":
            case "find":
            {
                var keyword = parts.Length > 1 ? parts[1].ToLowerInvariant() : "";
                if (string.IsNullOrWhiteSpace(keyword))
                {
                    items.Add(new LauncherItem("검색어 입력", "예: startup search teams", null, null, Symbol: "\uE783"));
                    break;
                }
                var filtered = allEntries.Where(e =>
                    e.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
                    e.Command.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count == 0)
                    items.Add(new LauncherItem("결과 없음", $"'{keyword}' 항목 없음", null, null, Symbol: "\uE946"));
                else
                    foreach (var e in filtered)
                        items.Add(MakeEntryItem(e));
                break;
            }

            default:
            {
                // 검색어로 처리
                var keyword = q.ToLowerInvariant();
                var filtered = allEntries.Where(e =>
                    e.Name.Contains(keyword, StringComparison.OrdinalIgnoreCase) ||
                    e.Command.Contains(keyword, StringComparison.OrdinalIgnoreCase)).ToList();

                if (filtered.Count == 0)
                    items.Add(new LauncherItem("결과 없음", $"'{q}' 항목 없음", null, null, Symbol: "\uE946"));
                else
                    foreach (var e in filtered.Take(15))
                        items.Add(MakeEntryItem(e));
                break;
            }
        }

        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("Startup", "클립보드에 복사했습니다.");
                }
                catch { /* 비핵심 */ }
                break;

            case ("open_folder", string path):
                var folderPath = string.IsNullOrEmpty(path) ? GetStartupFolderUser() : path;
                try
                {
                    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                    {
                        FileName        = folderPath,
                        UseShellExecute = true,
                    });
                }
                catch (Exception ex)
                {
                    NotificationService.Notify("Startup", $"폴더 열기 실패: {ex.Message}");
                }
                break;
        }
        return Task.CompletedTask;
    }

    // ── 레지스트리 수집 ────────────────────────────────────────────────────────

    private record StartupEntry(string Name, string Command, string Scope, string Source);

    private static List<StartupEntry> CollectAllEntries()
    {
        var result = new List<StartupEntry>();

        // HKCU
        foreach (var (regPath, scope) in RegKeys)
            result.AddRange(ReadRegistryRun(Registry.CurrentUser, regPath, scope));

        // HKLM
        foreach (var (regPath, scope) in RegKeysHKLM)
            result.AddRange(ReadRegistryRun(Registry.LocalMachine, regPath, scope));

        // 시작 폴더 (현재 사용자)
        result.AddRange(ReadStartupFolder(GetStartupFolderUser(), "현재 사용자 (폴더)"));

        // 시작 폴더 (모든 사용자)
        result.AddRange(ReadStartupFolder(GetStartupFolderCommon(), "모든 사용자 (폴더)"));

        return result;
    }

    private static IEnumerable<StartupEntry> ReadRegistryRun(RegistryKey hive, string path, string scope)
    {
        RegistryKey? key;
        try { key = hive.OpenSubKey(path, writable: false); }
        catch { yield break; }

        if (key == null) yield break;

        using (key)
        {
            foreach (var name in key.GetValueNames())
            {
                var cmd = key.GetValue(name)?.ToString() ?? "";
                yield return new StartupEntry(name, cmd, scope, path);
            }
        }
    }

    private static IEnumerable<StartupEntry> ReadStartupFolder(string folderPath, string scope)
    {
        if (!Directory.Exists(folderPath)) yield break;
        foreach (var file in Directory.EnumerateFiles(folderPath, "*.lnk"))
        {
            yield return new StartupEntry(
                Path.GetFileNameWithoutExtension(file),
                file,
                scope,
                folderPath);
        }
    }

    private static string GetStartupFolderUser() =>
        Environment.GetFolderPath(Environment.SpecialFolder.Startup);

    private static string GetStartupFolderCommon() =>
        Environment.GetFolderPath(Environment.SpecialFolder.CommonStartup);

    private static LauncherItem MakeEntryItem(StartupEntry e)
    {
        var cmdShort = e.Command.Length > 70 ? e.Command[..70] + "…" : e.Command;
        return new LauncherItem(
            e.Name,
            $"{e.Scope}  ·  {cmdShort}",
            null,
            ("copy", e.Command),
            Symbol: "\uE7FC");
    }
}
