import ctypes
from ctypes import wintypes
import time
import subprocess
import os
import struct
from PIL import Image

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

def attach_desktop():
    hwinsta = user32.OpenWindowStationW("WinSta0", False, 0x10000000)
    if hwinsta:
        user32.SetProcessWindowStation(hwinsta)
    hdesk = user32.OpenDesktopW("Default", 0, False, 0x10000000)
    if hdesk:
        user32.SetThreadDesktop(hdesk)

attach_desktop()

print("=== 1. KILL EXISTING VISUAL TOOL PROCESSES ===")
res = subprocess.run(["powershell", "-Command", "Stop-Process -Name 'AutoPOE2_VisualTool*' -Force -ErrorAction SilentlyContinue"], capture_output=True, text=True)
print("Stop-Process result:", res.returncode)
time.sleep(1.0)

print("\n=== 2. LAUNCH NEW AutoPOE2_VisualTool.exe ===")
exe_path = r"C:\Projects\AutoPOE2\bin\Release\AutoPOE2_VisualTool.exe"
proc = subprocess.Popen([exe_path, "--max-zoom", "8.0"])
print(f"Launched AutoPOE2_VisualTool.exe, Subprocess PID: {proc.pid}")

# Wait for tool to initialize and attach to game
print("Waiting 3 seconds for tool initialization and IPC creation...")
time.sleep(3.0)

print("\n=== 3. READ IPC STATUS ===")
FILE_MAP_READ = 0x0004
OpenFileMappingW = kernel32.OpenFileMappingW
OpenFileMappingW.restype = wintypes.HANDLE
OpenFileMappingW.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.LPCWSTR]

MapViewOfFile = kernel32.MapViewOfFile
MapViewOfFile.restype = wintypes.LPVOID
MapViewOfFile.argtypes = [wintypes.HANDLE, wintypes.DWORD, wintypes.DWORD, wintypes.DWORD, ctypes.c_size_t]

h_map = OpenFileMappingW(FILE_MAP_READ, False, "Local\\AutoPOE2_VisualTool_v1")
if not h_map:
    print(f"Failed to open IPC mapping: {ctypes.get_last_error()}")
else:
    ptr = MapViewOfFile(h_map, FILE_MAP_READ, 0, 0, 48)
    if ptr:
        data = ctypes.string_at(ptr, 48)
        magic, seq, cap, cur, flags, st, cam, fog, pid, err = struct.unpack('<IIffIIQQII', data)
        print(f"IPC Read: magic=0x{magic:08X}, cap={cap:.1f}x, cur={cur:.1f}x, flags=0x{flags:08X}, status=0x{st:08X}, cam=0x{cam:016X}, fog=0x{fog:016X}, pid={pid}")
        kernel32.UnmapViewOfFile(ptr)
    kernel32.CloseHandle(h_map)

print("\n=== 4. SWITCH TAB / FOCUS POE2 WINDOW ===")
hwnd = user32.FindWindowW("POEWindowClass", None)
if not hwnd:
    hwnd = user32.FindWindowW(None, "Path of Exile 2")
print(f"Found POE2 HWND: {hwnd} (0x{hwnd:08X})")

if hwnd:
    SW_RESTORE = 9
    user32.ShowWindow(hwnd, SW_RESTORE)
    user32.SetForegroundWindow(hwnd)
    user32.BringWindowToTop(hwnd)
    user32.SetActiveWindow(hwnd)
    time.sleep(0.5)

    fg = user32.GetForegroundWindow()
    print(f"Foreground HWND after focus: {fg} (Matches POE2: {fg == hwnd})")

print("\n=== 5. SIMULATE MOUSE WHEEL SCROLLS ===")
MOUSEEVENTF_WHEEL = 0x0800
WHEEL_DELTA = 120

# Scroll down 10 notches (delta -120 each) to zoom out
for i in range(10):
    user32.mouse_event(MOUSEEVENTF_WHEEL, 0, 0, -WHEEL_DELTA, 0)
    time.sleep(0.08)

print("Sent 10 scroll-down mouse events.")
time.sleep(1.0)

print("\n=== 6. READ IPC STATUS AFTER SCROLL ===")
h_map = OpenFileMappingW(FILE_MAP_READ, False, "Local\\AutoPOE2_VisualTool_v1")
if h_map:
    ptr = MapViewOfFile(h_map, FILE_MAP_READ, 0, 0, 48)
    if ptr:
        data = ctypes.string_at(ptr, 48)
        magic, seq, cap, cur, flags, st, cam, fog, pid, err = struct.unpack('<IIffIIQQII', data)
        print(f"IPC After Scroll: magic=0x{magic:08X}, cap={cap:.1f}x, cur={cur:.1f}x, flags=0x{flags:08X}, status=0x{st:08X}, cam=0x{cam:016X}, fog=0x{fog:016X}, pid={pid}")
        kernel32.UnmapViewOfFile(ptr)
    kernel32.CloseHandle(h_map)

print("\n=== 7. CAPTURE DESKTOP / GAME SCREEN ===")
rect = wintypes.RECT()
user32.GetWindowRect(hwnd if hwnd else 0, ctypes.byref(rect))
w = rect.right - rect.left
h = rect.bottom - rect.top
print(f"Window rect: ({rect.left}, {rect.top}) -> ({rect.right}, {rect.bottom}), size: {w}x{h}")

desk_dc = user32.GetDC(0)
mem_dc = gdi32.CreateCompatibleDC(desk_dc)
bmp = gdi32.CreateCompatibleBitmap(desk_dc, w, h)
old_bmp = gdi32.SelectObject(mem_dc, bmp)

SRCCOPY = 0x00CC0020
ok = gdi32.BitBlt(mem_dc, 0, 0, w, h, desk_dc, rect.left, rect.top, SRCCOPY)
print(f"BitBlt capture ok: {ok}")

class BITMAPINFOHEADER(ctypes.Structure):
    _fields_ = [
        ('biSize', wintypes.DWORD),
        ('biWidth', wintypes.LONG),
        ('biHeight', wintypes.LONG),
        ('biPlanes', wintypes.WORD),
        ('biBitCount', wintypes.WORD),
        ('biCompression', wintypes.DWORD),
        ('biSizeImage', wintypes.DWORD),
        ('biXPelsPerMeter', wintypes.LONG),
        ('biYPelsPerMeter', wintypes.LONG),
        ('biClrUsed', wintypes.DWORD),
        ('biClrImportant', wintypes.DWORD)
    ]

class BITMAPINFO(ctypes.Structure):
    _fields_ = [
        ('bmiHeader', BITMAPINFOHEADER),
        ('bmiColors', wintypes.DWORD * 3)
    ]

bmi = BITMAPINFO()
bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
bmi.bmiHeader.biWidth = w
bmi.bmiHeader.biHeight = -h
bmi.bmiHeader.biPlanes = 1
bmi.bmiHeader.biBitCount = 32
bmi.bmiHeader.biCompression = 0

buf_size = w * h * 4
raw_buf = ctypes.create_string_buffer(buf_size)
lines = gdi32.GetDIBits(mem_dc, bmp, 0, h, raw_buf, ctypes.byref(bmi), 0)

img = Image.frombuffer("RGBA", (w, h), raw_buf, "raw", "BGRA", 0, 1)
out_path = "captures/live_zoom_verified.png"
img.save(out_path)
print(f"Screenshot successfully saved to: {out_path} ({img.size})")

gdi32.SelectObject(mem_dc, old_bmp)
gdi32.DeleteObject(bmp)
gdi32.DeleteDC(mem_dc)
user32.ReleaseDC(0, desk_dc)

print("\n=== EXECUTION FINISHED ===")
