using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using AxCopilot.SDK;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 윈도우 포커스 스위처 핸들러. "win" 프리픽스로 사용합니다.
/// 열린 창 목록을 타이틀/프로세스명으로 검색하여 즉시 전환합니다.
/// 예: win          → 열린 창 목록
///     win chrome   → Chrome 창 필터
///     win 보고서    → 타이틀에 "보고서" 포함하는 창
/// Enter → 해당 창으로 즉시 전환.
/// </summary>
public class WindowSwitchHandler : IActionHandler
{
    public string? Prefix => "win";

    public PluginMetadata Metadata => new(
        "WindowSwitch",
        "윈도우 포커스 스위처 — win",
        "1.0",
        "AX");

    [DllImport("user32.dll")] private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
    [DllImport("user32.dll")] private static extern bool IsWindowVisible(IntPtr hWnd);
    [DllImport("user32.dll")] private static extern int GetWindowTextLength(IntPtr hWnd);
    [DllImport("user32.dll")] private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
    [DllImport("user32.dll")] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
    [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd);
    [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
    [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd);
    [DllImport("user32.dll")] private static extern IntPtr GetShellWindow();

    private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
    private const int SW_RESTORE = 9;

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

        if (!string.IsNullOrWhiteSpace(q))
        {
            windows = windows.Where(w =>
                w.Title.Contains(q, StringComparison.OrdinalIgnoreCase) ||
                w.ProcessName.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
        }

        if (!windows.Any())
        {
            return Task.FromResult<IEnumerable<LauncherItem>>(
            [
                new LauncherItem(
                    string.IsNullOrWhiteSpace(q) ? "열린 창이 없습니다" : $"'{q}'에 해당하는 창 없음",
                    "win 뒤에 프로세스명 또는 창 제목 입력",
                    null, null, Symbol: Symbols.Info)
            ]);
        }

        var items = windows.Take(15).Select(w => new LauncherItem(
            w.Title.Length > 60 ? w.Title[..57] + "…" : w.Title,
            $"{w.ProcessName}  ·  {(w.IsMinimized ? "[최소화됨]  ·  " : "")}Enter → 전환",
            null, w.Handle,
            Symbol: Symbols.Computer)).ToList<LauncherItem>();

        items.Insert(0, new LauncherItem(
            $"열린 창 {windows.Count}개",
            "Enter → 해당 창으로 즉시 전환",
            null, null, Symbol: Symbols.Info));

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

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is IntPtr hwnd && hwnd != IntPtr.Zero)
        {
            if (IsIconic(hwnd))
                ShowWindow(hwnd, SW_RESTORE);
            SetForegroundWindow(hwnd);
        }
        return Task.CompletedTask;
    }

    private static List<WindowInfo> GetOpenWindows()
    {
        var list = new List<WindowInfo>();
        var shellWnd = GetShellWindow();
        var currentProcessName = Process.GetCurrentProcess().ProcessName;

        EnumWindows((hWnd, _) =>
        {
            if (hWnd == shellWnd) return true;
            if (!IsWindowVisible(hWnd)) return true;

            var titleLen = GetWindowTextLength(hWnd);
            if (titleLen == 0) return true;

            var sb = new StringBuilder(titleLen + 1);
            GetWindowText(hWnd, sb, sb.Capacity);
            var title = sb.ToString();

            string processName = "";
            try
            {
                GetWindowThreadProcessId(hWnd, out uint pid);
                processName = Process.GetProcessById((int)pid).ProcessName;
            }
            catch (Exception) { }

            // 자기 자신 + 시스템 프로세스 제외
            if (processName == currentProcessName)
                return true;
            if (processName is "ApplicationFrameHost" or "ShellExperienceHost" or "SearchHost"
                or "StartMenuExperienceHost" or "TextInputHost")
                return true;

            list.Add(new WindowInfo(hWnd, title, processName, IsIconic(hWnd)));
            return true;
        }, IntPtr.Zero);

        return list;
    }

    private record WindowInfo(IntPtr Handle, string Title, string ProcessName, bool IsMinimized);
}
