"""
Tiện ích Chuyển Đổi & Xem Trực Tiếp Desktop Ảo Chạy Test Game Path of Exile 2
Hỗ trợ:
- Kiểm tra trạng thái các Desktop trong Windows Window Station (WinSta0).
- Chuyển màn hình vật lý sang Desktop ảo để xem hiện trạng game trực tiếp (Peek / Toggle).
- Tự động quay về Desktop chính (Default) an toàn sau số giây định trước (Failsafe Auto-Revert).

Cách dùng:
  python scripts/toggle_desktop.py --status
  python scripts/toggle_desktop.py --peek 10
  python scripts/toggle_desktop.py --toggle
"""

import argparse
import ctypes
import sys
import time
from typing import List, Optional, Tuple

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8")

user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32

DESKTOP_SWITCHDESKTOP = 0x0100
GENERIC_ALL = 0x10000000
UOI_NAME = 2


def get_current_desktop_name() -> str:
    """Lấy tên của Desktop mà thread hiện tại đang gắn."""
    h_curr = user32.GetThreadDesktop(kernel32.GetCurrentThreadId())
    if not h_curr:
        return "Unknown"
    buf = ctypes.create_unicode_buffer(256)
    needed = ctypes.c_ulong()
    user32.GetUserObjectInformationW(h_curr, UOI_NAME, buf, 256, ctypes.byref(needed))
    return buf.value


def enum_all_desktops() -> List[str]:
    """Liệt kê toàn bộ Desktop trong Process Window Station hiện tại."""
    hwinsta = user32.GetProcessWindowStation()
    if not hwinsta:
        return []
    desktops = []
    DESKTOPENUMPROC = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_wchar_p, ctypes.c_void_p)

    def cb(name, lparam):
        desktops.append(name)
        return True

    user32.EnumDesktopsW(hwinsta, DESKTOPENUMPROC(cb), 0)
    return desktops


def find_game_desktop() -> Tuple[Optional[str], Optional[int]]:
    """Tìm Desktop đang chứa cửa sổ Path of Exile 2 hoặc các desktop exebox-*."""
    hwinsta = user32.GetProcessWindowStation()
    desktops = enum_all_desktops()

    WNDENUMPROC = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_void_p)

    for desk_name in desktops:
        if desk_name.lower() == "default":
            continue

        h = user32.OpenDesktopW(desk_name, 0, False, GENERIC_ALL)
        if not h:
            continue

        found_poe = []

        def wnd_cb(hwnd, lparam):
            length = user32.GetWindowTextLengthW(hwnd)
            buf = ctypes.create_unicode_buffer(length + 1)
            user32.GetWindowTextW(hwnd, buf, length + 1)
            title = buf.value

            cls_buf = ctypes.create_unicode_buffer(256)
            user32.GetClassNameW(hwnd, cls_buf, 256)
            cls = cls_buf.value

            if "path of exile" in title.lower() or "poewindowclass" in cls.lower():
                found_poe.append(hwnd)
            return True

        user32.EnumDesktopWindows(h, WNDENUMPROC(wnd_cb), 0)
        user32.CloseDesktop(h)

        if found_poe:
            return desk_name, found_poe[0]

    # Nếu không tìm thấy cửa sổ cụ thể, trả về desktop exebox đầu tiên nếu có
    for desk_name in desktops:
        if desk_name.startswith("exebox-") or "autopoe" in desk_name.lower():
            return desk_name, None

    return None, None


def switch_to_desktop(desktop_name: str) -> bool:
    """Chuyển màn hình vật lý sang Desktop chỉ định."""
    h_desk = user32.OpenDesktopW(desktop_name, 0, False, DESKTOP_SWITCHDESKTOP)
    if not h_desk:
        print(f"[Error] Không thể mở desktop '{desktop_name}'. Lỗi: {ctypes.GetLastError()}")
        return False
    res = user32.SwitchDesktop(h_desk)
    user32.CloseDesktop(h_desk)
    return bool(res)


def peek_desktop(seconds: int = 10):
    """
    Chuyển màn hình sang Desktop ảo trong N giây để xem hiện trạng,
    sau đó tự động chuyển ngược lại về Desktop chính (Default).
    """
    target_desk, hwnd = find_game_desktop()
    if not target_desk:
        print("[Info] Không phát hiện Desktop ảo nào đang chạy game.")
        print(f"Các desktop hiện có: {enum_all_desktops()}")
        return

    print(f"[*] Tìm thấy Desktop game: '{target_desk}' (HWND: {hwnd})")
    print(f"[*] Đang chuyển màn hình sang '{target_desk}' trong {seconds} giây...")
    print("[*] (Hệ thống sẽ TỰ ĐỘNG chuyển lại về Default sau khi hết thời gian để an toàn).")

    if not switch_to_desktop(target_desk):
        print("[Error] Chuyển desktop thất bại.")
        return

    time.sleep(seconds)

    print("[*] Đang chuyển về Desktop chính 'Default'...")
    switch_to_desktop("Default")
    print("[*] Đã quay về Desktop 'Default' thành công.")


def toggle_desktop():
    """Chuyển đổi qua lại giữa Default và Desktop ảo."""
    curr = get_current_desktop_name()
    target_desk, _ = find_game_desktop()
    if not target_desk:
        print("[Info] Không tìm thấy Desktop ảo nào khác 'Default'.")
        return

    if curr.lower() == "default":
        print(f"[*] Đang chuyển sang '{target_desk}'...")
        switch_to_desktop(target_desk)
    else:
        print("[*] Đang chuyển về 'Default'...")
        switch_to_desktop("Default")


def print_status():
    """Hiển thị thông tin toàn bộ Desktop và vị trí game."""
    desktops = enum_all_desktops()
    curr = get_current_desktop_name()
    target_desk, hwnd = find_game_desktop()

    print("=" * 60)
    print(" BÁO CÁO HIỆN TRẠNG WINDOWS DESKTOP - AUTOPOE2")
    print("=" * 60)
    print(f"- Desktop thread hiện tại  : {curr}")
    print(f"- Toàn bộ Desktop tìm thấy : {desktops}")
    if target_desk:
        print(f"- Desktop chứa game POE2   : {target_desk}")
        print(f"- POE2 Window HWND         : {hwnd if hwnd else 'Chưa mở cửa sổ'}")
    else:
        print("- Không phát hiện Desktop ảo nào đang chứa game POE2.")
    print("=" * 60)


def main():
    parser = argparse.ArgumentParser(description="AutoPOE2 Virtual Desktop Switcher & Viewer")
    parser.add_argument("--status", action="store_true", help="Kiểm tra trạng thái các Desktop")
    parser.add_argument("--peek", type=int, default=0, help="Xem desktop game trong N giây rồi tự quay về")
    parser.add_argument("--toggle", action="store_true", help="Chuyển đổi giữa Default và Desktop ảo")
    args = parser.parse_args()

    if args.status:
        print_status()
    elif args.peek > 0:
        peek_desktop(args.peek)
    elif args.toggle:
        toggle_desktop()
    else:
        print_status()
        print("\nGợi ý lệnh:")
        print("  python scripts/toggle_desktop.py --peek 10    (Xem 10s rồi tự về màn hình chính)")
        print("  python scripts/toggle_desktop.py --toggle     (Chuyển đổi qua lại)")


if __name__ == "__main__":
    main()
