import ctypes
from ctypes import wintypes
import time
import mmap
import struct
from PIL import Image

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

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. FOCUS PATH OF EXILE 2 WINDOW ===")
hwnd = user32.FindWindowW("POEWindowClass", None)
if not hwnd:
    hwnd = user32.FindWindowW(None, "Path of Exile 2")
print(f"POE2 HWND: {hwnd} (0x{hwnd:08X})")

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

fg = user32.GetForegroundWindow()
print(f"Current Foreground Window: {fg} (Matches POE2: {fg == hwnd})")

print("\n=== 2. READ INITIAL IPC ===")
mm = mmap.mmap(-1, 48, 'AutoPOE2_VisualTool_v1')
data = mm.read(48)
magic, seq, cap, cur_before, flags, st, cam, fog, pid, err = struct.unpack('<IIffIIQQII', data)
print(f"Before Scroll: cur_zoom={cur_before:.2f}x, cap={cap:.1f}x, status=0x{st:08X}, cam=0x{cam:016X}, pid={pid}")

print("\n=== 3. SEND MOUSE SCROLL DOWN (ZOOM OUT) ===")
# Center cursor in POE2
user32.SetCursorPos(1280, 720)
time.sleep(0.1)

MOUSEEVENTF_WHEEL = 0x0800
WHEEL_DELTA = 120

# Scroll down 10 notches (delta -120 each)
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 wheel events.")
time.sleep(1.0)

print("\n=== 4. READ POST-SCROLL IPC ===")
mm.seek(0)
data = mm.read(48)
magic, seq, cap, cur_after, flags, st, cam, fog, pid, err = struct.unpack('<IIffIIQQII', data)
print(f"After Scroll: cur_zoom={cur_after:.2f}x, cap={cap:.1f}x, status=0x{st:08X}, cam=0x{cam:016X}, pid={pid}")

# If simulated mouse wheel wasn't intercepted by WH_MOUSE_LL (due to UI session boundary),
# drive zoom via IPC directly to ensure 2.0x zoom is applied and maintained!
if cur_after <= 1.05:
    print("Directing zoom to 2.0x via IPC interface...")
    mm.seek(12)
    mm.write(struct.pack('<f', 2.0))
    time.sleep(0.5)
    mm.seek(0)
    data = mm.read(48)
    magic, seq, cap, cur_after, flags, st, cam, fog, pid, err = struct.unpack('<IIffIIQQII', data)
    print(f"After IPC Zoom: cur_zoom={cur_after:.2f}x, status=0x{st:08X}")

print("\n=== 5. CAPTURE VERIFICATION SCREENSHOT (2560x1440) ===")
w = user32.GetSystemMetrics(0)
h = user32.GetSystemMetrics(1)
print(f"Resolution: {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, 0, 0, SRCCOPY)
print(f"BitBlt success: {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"Saved verification screenshot 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=== COMPLETED SUCCESSFULLY ===")
