import os
import sys
import time
import math
import ctypes
from ctypes import wintypes

sys.path.insert(0, r"c:\Projects\AutoPOE2")

from src.assistant_tool.core_shm_bridge import CoreShmBridge
from src.common.win32_window import find_poe2_window, get_client_rect
from src.common.virtual_display_manager import capture_virtual_display

user32 = ctypes.windll.user32

WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
WM_MOUSEMOVE = 0x0200
WM_LBUTTONDOWN = 0x0201
WM_LBUTTONUP = 0x0202
WM_ACTIVATE = 0x0006
WM_SETFOCUS = 0x0007
WM_NCACTIVATE = 0x0086
WM_MOUSEACTIVATE = 0x0021
WA_ACTIVE = 1
WA_CLICKACTIVE = 2
MK_LBUTTON = 0x0001

VK_W = 0x57
SC_W = 0x11
VK_A = 0x41
SC_A = 0x1E
VK_S = 0x53
SC_S = 0x1F
VK_D = 0x44
SC_D = 0x20

def get_pos(bridge):
    snap = bridge.read_telemetry_snapshot()
    return (snap.player.pos_x, snap.player.pos_z)

def test_method(name, fn, bridge, hwnd):
    p1 = get_pos(bridge)
    print(f"\n--- Testing {name} ---")
    print(f"Pos before: ({p1[0]:.2f}, {p1[1]:.2f})")
    fn(hwnd)
    time.sleep(0.3)
    p2 = get_pos(bridge)
    print(f"Pos after:  ({p2[0]:.2f}, {p2[1]:.2f})")
    dist = math.hypot(p2[0] - p1[0], p2[1] - p1[1])
    print(f"Delta dist: {dist:.4f}")
    if dist > 0.5:
        print(f"SUCCESS! Player moved {dist:.2f} units with {name}!")
        return True
    else:
        print(f"No movement detected.")
        return False

bridge = CoreShmBridge()
hwnd = find_poe2_window()
print(f"Target HWND: {hex(hwnd)}, Client Rect: {get_client_rect(hwnd)}")
p_initial = get_pos(bridge)
print(f"Initial Pos: ({p_initial[0]:.2f}, {p_initial[1]:.2f})")

# Method 1: Plain PostMessage WM_KEYDOWN
def m1_plain_postmessage(h):
    lparam_down = (SC_W << 16) | 1
    lparam_up = (SC_W << 16) | 0xC0000001
    for _ in range(20):
        user32.PostMessageW(h, WM_KEYDOWN, VK_W, lparam_down)
        time.sleep(0.04)
    user32.PostMessageW(h, WM_KEYUP, VK_W, lparam_up)

# Method 2: Send WM_ACTIVATE then PostMessage
def m2_activate_then_postmessage(h):
    user32.SendMessageW(h, WM_NCACTIVATE, 1, 0)
    user32.SendMessageW(h, WM_ACTIVATE, WA_ACTIVE, 0)
    user32.SendMessageW(h, WM_SETFOCUS, 0, 0)
    lparam_down = (SC_W << 16) | 1
    lparam_up = (SC_W << 16) | 0xC0000001
    for _ in range(20):
        user32.PostMessageW(h, WM_KEYDOWN, VK_W, lparam_down)
        time.sleep(0.04)
    user32.PostMessageW(h, WM_KEYUP, VK_W, lparam_up)

# Method 3: Mouse click on ground (offset from center)
def m3_click_ground(h):
    # Player is near center (960, 540). Click 150px to the north (960, 390)
    cx, cy = 960, 390
    lp = (cy << 16) | cx
    user32.PostMessageW(h, WM_MOUSEACTIVATE, h, (WM_LBUTTONDOWN << 16) | 1)
    user32.PostMessageW(h, WM_MOUSEMOVE, 0, lp)
    time.sleep(0.03)
    user32.PostMessageW(h, WM_LBUTTONDOWN, MK_LBUTTON, lp)
    time.sleep(0.08)
    user32.PostMessageW(h, WM_LBUTTONUP, 0, lp)

# Method 4: Hold LMB on ground for 500ms
def m4_hold_lmb_ground(h):
    cx, cy = 960, 350
    lp = (cy << 16) | cx
    user32.PostMessageW(h, WM_MOUSEMOVE, 0, lp)
    user32.PostMessageW(h, WM_LBUTTONDOWN, MK_LBUTTON, lp)
    for _ in range(15):
        time.sleep(0.04)
        user32.PostMessageW(h, WM_MOUSEMOVE, MK_LBUTTON, lp)
    user32.PostMessageW(h, WM_LBUTTONUP, 0, lp)

# Method 5: Double click on ground
def m5_dblclick_ground(h):
    cx, cy = 960, 350
    lp = (cy << 16) | cx
    WM_LBUTTONDBLCLK = 0x0203
    user32.PostMessageW(h, WM_LBUTTONDOWN, MK_LBUTTON, lp)
    time.sleep(0.04)
    user32.PostMessageW(h, WM_LBUTTONUP, 0, lp)
    time.sleep(0.04)
    user32.PostMessageW(h, WM_LBUTTONDBLCLK, MK_LBUTTON, lp)
    time.sleep(0.04)
    user32.PostMessageW(h, WM_LBUTTONUP, 0, lp)

test_method("M1: Plain PostMessage WM_KEYDOWN", m1_plain_postmessage, bridge, hwnd)
test_method("M2: Activate + PostMessage WM_KEYDOWN", m2_activate_then_postmessage, bridge, hwnd)
test_method("M3: Click Ground (960, 390)", m3_click_ground, bridge, hwnd)
test_method("M4: Hold LMB Ground (960, 350)", m4_hold_lmb_ground, bridge, hwnd)
test_method("M5: DblClick Ground (960, 350)", m5_dblclick_ground, bridge, hwnd)
