using System.Runtime.InteropServices;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 창 스냅/레이아웃 핸들러. "snap" 프리픽스로 사용합니다.
/// 런처 호출 직전의 활성 창을 대상으로 배치합니다.
///
/// 예: snap left    → 화면 왼쪽 절반
///     snap right   → 화면 오른쪽 절반
///     snap top     → 화면 위쪽 절반
///     snap bottom  → 화면 아래쪽 절반
///     snap full    → 전체 화면 (최대화)
///     snap tl      → 좌상단 1/4
///     snap tr      → 우상단 1/4
///     snap bl      → 좌하단 1/4
///     snap br      → 우하단 1/4
///     snap center  → 화면 중앙 (80% 크기)
///     snap restore → 이전 크기/위치로 복원
/// </summary>
public class SnapHandler : IActionHandler
{
    public string? Prefix => "snap";

    public PluginMetadata Metadata => new(
        "WindowSnap",
        "창 배치 — 2/3/4분할, 1/3·2/3, 전체화면, 중앙, 복원",
        "1.1",
        "AX");

    // ─── P/Invoke ──────────────────────────────────────────────────────────────

    [DllImport("user32.dll")] private static extern bool SetWindowPos(
        IntPtr hWnd, IntPtr hWndInsertAfter,
        int x, int y, int cx, int cy, uint uFlags);

    [DllImport("user32.dll")] private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")] private static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);

    [DllImport("user32.dll")] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);

    [DllImport("user32.dll")] private static extern bool IsWindow(IntPtr hWnd);

    [DllImport("user32.dll")] private static extern bool IsIconic(IntPtr hWnd);

    [StructLayout(LayoutKind.Sequential)]
    private struct RECT { public int left, top, right, bottom; }

    [StructLayout(LayoutKind.Sequential)]
    private struct MONITORINFO
    {
        public int cbSize;
        public RECT rcMonitor;
        public RECT rcWork;  // 작업표시줄 제외 영역
        public uint dwFlags;
    }

    private const uint SWP_SHOWWINDOW = 0x0040;
    private const uint SWP_NOZORDER = 0x0004;
    private const uint MONITOR_DEFAULTTONEAREST = 0x00000002;
    private const int SW_RESTORE = 9;
    private const int SW_MAXIMIZE = 3;

    private static readonly (string Key, string Label, string Desc)[] _snapOptions =
    [
        // ── 2분할 ──
        ("left",    "왼쪽 절반",    "화면 왼쪽 50% 영역에 배치"),
        ("right",   "오른쪽 절반",  "화면 오른쪽 50% 영역에 배치"),
        ("top",     "위쪽 절반",    "화면 위쪽 50% 영역에 배치"),
        ("bottom",  "아래쪽 절반",  "화면 아래쪽 50% 영역에 배치"),
        // ── 4분할 ──
        ("tl",      "좌상단 1/4",   "화면 좌상단 25% 영역에 배치"),
        ("tr",      "우상단 1/4",   "화면 우상단 25% 영역에 배치"),
        ("bl",      "좌하단 1/4",   "화면 좌하단 25% 영역에 배치"),
        ("br",      "우하단 1/4",   "화면 우하단 25% 영역에 배치"),
        // ── 3분할 (좌 50% + 우 상하) ──
        ("l-rt",    "좌반 + 우상",  "왼쪽 50% + 오른쪽 상단 25% (2창용)"),
        ("l-rb",    "좌반 + 우하",  "왼쪽 50% + 오른쪽 하단 25% (2창용)"),
        ("r-lt",    "우반 + 좌상",  "오른쪽 50% + 왼쪽 상단 25% (2창용)"),
        ("r-lb",    "우반 + 좌하",  "오른쪽 50% + 왼쪽 하단 25% (2창용)"),
        // ── 3등분 (가로) ──
        ("third-l", "좌측 1/3",     "화면 왼쪽 33% 영역에 배치"),
        ("third-c", "중앙 1/3",     "화면 가운데 33% 영역에 배치"),
        ("third-r", "우측 1/3",     "화면 오른쪽 33% 영역에 배치"),
        // ── 2/3 + 1/3 ──
        ("two3-l",  "좌측 2/3",     "화면 왼쪽 66% 영역에 배치"),
        ("two3-r",  "우측 2/3",     "화면 오른쪽 66% 영역에 배치"),
        // ── 기타 ──
        ("full",    "전체 화면",    "최대화"),
        ("center",  "화면 중앙",    "화면 중앙 80% 크기로 배치"),
        ("restore", "원래 크기 복원", "창을 이전 크기로 복원"),
    ];

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q = query.Trim().ToLowerInvariant();
        var hwnd = WindowTracker.PreviousWindow;
        var windowValid = hwnd != IntPtr.Zero && IsWindow(hwnd);

        var hint = windowValid ? "Enter로 현재 활성 창에 적용" : "대상 창 없음 — 런처를 열기 전 창에 적용됩니다";

        IEnumerable<(string Key, string Label, string Desc)> options = string.IsNullOrWhiteSpace(q)
            ? _snapOptions
            : _snapOptions.Where(o => o.Key.StartsWith(q) || o.Label.Contains(q));

        var items = options.Select(o => new LauncherItem(
            o.Label,
            $"{o.Desc}  ·  {hint}",
            null,
            o.Key,
            Symbol: Symbols.SnapLayout)).ToList<LauncherItem>();

        if (!items.Any())
            items.Add(new LauncherItem(
                $"알 수 없는 스냅 방향: {q}",
                "left / right / tl / tr / bl / br / third-l/c/r / two3-l/r / full / center / restore",
                null, null, Symbol: Symbols.Warning));

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

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is not string snapKey) return;

        var hwnd = WindowTracker.PreviousWindow;
        if (hwnd == IntPtr.Zero || !IsWindow(hwnd)) return;

        // 최대화/아이콘화 상태면 먼저 복원
        if (IsIconic(hwnd))
            ShowWindow(hwnd, SW_RESTORE);

        // 잠시 대기 (런처 닫힘 애니메이션 후 적용)
        await Task.Delay(80, ct);

        ApplySnap(hwnd, snapKey);
    }

    private static void ApplySnap(IntPtr hwnd, string key)
    {
        // 창이 속한 모니터의 작업 영역 가져오기
        var hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        var mi = new MONITORINFO { cbSize = Marshal.SizeOf<MONITORINFO>() };
        if (!GetMonitorInfo(hMonitor, ref mi)) return;

        var w = mi.rcWork;
        int mw = w.right - w.left;
        int mh = w.bottom - w.top;
        int mx = w.left;
        int my = w.top;

        if (key == "full")
        {
            ShowWindow(hwnd, SW_MAXIMIZE);
            return;
        }

        if (key == "restore")
        {
            ShowWindow(hwnd, SW_RESTORE);
            return;
        }

        var (x, y, cw, ch) = key switch
        {
            // 2분할
            "left"    => (mx,               my,               mw / 2,         mh),
            "right"   => (mx + mw / 2,      my,               mw / 2,         mh),
            "top"     => (mx,               my,               mw,             mh / 2),
            "bottom"  => (mx,               my + mh / 2,      mw,             mh / 2),
            // 4분할
            "tl"      => (mx,               my,               mw / 2,         mh / 2),
            "tr"      => (mx + mw / 2,      my,               mw / 2,         mh / 2),
            "bl"      => (mx,               my + mh / 2,      mw / 2,         mh / 2),
            "br"      => (mx + mw / 2,      my + mh / 2,      mw / 2,         mh / 2),
            // 3분할 (좌반 + 우상/우하)
            "l-rt"    => (mx + mw / 2,      my,               mw / 2,         mh / 2),
            "l-rb"    => (mx + mw / 2,      my + mh / 2,      mw / 2,         mh / 2),
            "r-lt"    => (mx,               my,               mw / 2,         mh / 2),
            "r-lb"    => (mx,               my + mh / 2,      mw / 2,         mh / 2),
            // 3등분
            "third-l" => (mx,               my,               mw / 3,         mh),
            "third-c" => (mx + mw / 3,      my,               mw / 3,         mh),
            "third-r" => (mx + mw * 2 / 3,  my,               mw / 3,         mh),
            // 2/3 + 1/3
            "two3-l"  => (mx,               my,               mw * 2 / 3,     mh),
            "two3-r"  => (mx + mw / 3,      my,               mw * 2 / 3,     mh),
            // 기타
            "center"  => (mx + mw / 10,     my + mh / 10,     mw * 8 / 10,    mh * 8 / 10),
            _         => (mx,               my,               mw,             mh)
        };

        // SW_RESTORE 후 SetWindowPos — 최대화 플래그 해제 필요
        ShowWindow(hwnd, SW_RESTORE);
        SetWindowPos(hwnd, IntPtr.Zero, x, y, cw, ch, SWP_SHOWWINDOW | SWP_NOZORDER);
    }
}
