import time
import math
import threading
import subprocess
import sys
import keyboard
import mouse
from config import (
    SCREEN_WIDTH,
    SCREEN_HEIGHT,
    JOYSTICK_CENTER_X,
    JOYSTICK_CENTER_Y,
    JOYSTICK_RADIUS,
    CAMERA_CONTROL_ENABLED,
    CAMERA_SENSITIVITY,
    CAMERA_STEP_PIXELS,
    CAMERA_DEAD_ZONE,
    CAMERA_START_X,
    CAMERA_START_Y,
    ADB_PATH
)

# ==================== 状态变量 ====================
current_keys = set()
is_touching = False
last_x = JOYSTICK_CENTER_X
last_y = JOYSTICK_CENTER_Y
running = True

# 疾跑状态
is_sprinting = False
sprint_end_time = 0.0

# 双击检测
DOUBLE_TAP_THRESHOLD = 0.3
w_press_times = []

# 视角控制状态
is_camera_touching = False
camera_touch_x = CAMERA_START_X
camera_touch_y = CAMERA_START_Y
last_mouse_x = 0
last_mouse_y = 0
right_button_down = False
accumulated_mouse_dx = 0
accumulated_mouse_dy = 0

# ADB shell 进程
adb_process = None

# 按键方向映射
# 根据用户测试：手动触控时，向前上滑、向后下滑、向左左滑、向右右滑
KEY_DIRECTIONS = {
    'w': (0, -1),   # W向前：向上滑
    's': (0, 1),    # S向后：向下滑
    'a': (-1, 0),   # A向左：向左滑
    'd': (1, 0),    # D向右：向右滑
}

# 互斥按键
MUTEX_KEYS = {
    'w': 's',
    's': 'w',
    'a': 'd',
    'd': 'a',
}

# 触摸 ID
JOYSTICK_TOUCH_ID = 0
CAMERA_TOUCH_ID = 1

# ==================== ADB 工具 ====================
def start_adb_shell():
    global adb_process
    try:
        adb_process = subprocess.Popen(
            [ADB_PATH, "shell"],
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            bufsize=0,
            universal_newlines=True
        )
        return True
    except Exception as e:
        print(f"Failed to start ADB shell: {e}")
        return False

def send_adb_command(cmd, wait_time=0):
    """发送 ADB 命令 - 使用 Popen 异步执行"""
    try:
        # 使用 Popen 异步执行，不等待完成
        full_cmd = [ADB_PATH, "shell", cmd]
        subprocess.Popen(
            full_cmd,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )
        if wait_time > 0:
            time.sleep(wait_time)
        return True
    except Exception as e:
        print(f"ADB command error: {e}")
        return False

def get_device_resolution():
    """获取手机实际分辨率 - 使用 adb shell 命令"""
    global adb_process
    # 直接使用 adb shell wm size 命令
    try:
        import subprocess as sp
        result = sp.run(
            [ADB_PATH, "shell", "wm", "size"],
            capture_output=True,
            text=True,
            timeout=5
        )
        output = result.stdout
        if "Physical" in output:
            for line in output.split('\n'):
                if "Physical" in line:
                    parts = line.split(":")[1].strip().split("x")
                    return int(parts[0]), int(parts[1])
        return None, None
    except Exception as e:
        print(f"Failed to get resolution: {e}")
        return None, None

def send_touch_down(x, y, touch_id=0):
    # 用短 swipe 模拟按下
    cmd = f"input swipe {x} {y} {x} {y} 50"
    send_adb_command(cmd)

def send_touch_move(x, y, touch_id=0):
    # 此函数不再使用，直接在 touch_joystick 中处理
    pass

def send_touch_up(x, y, touch_id=0):
    # 松开时发送一个短 swipe 确认释放
    cmd = f"input swipe {x} {y} {x} {y} 50"
    send_adb_command(cmd)

# ==================== 摇杆控制 ====================
def calculate_joystick_position():
    global is_sprinting, sprint_end_time
    
    # 检查疾跑是否过期
    if is_sprinting and time.time() > sprint_end_time:
        is_sprinting = False
    
    # 基础半径
    radius = JOYSTICK_RADIUS * 2 if is_sprinting else JOYSTICK_RADIUS
    
    # 计算方向向量
    dx = 0
    dy = 0
    
    for key in current_keys:
        if key in KEY_DIRECTIONS:
            dir_x, dir_y = KEY_DIRECTIONS[key]
            dx += dir_x
            dy += dir_y
    
    # 归一化
    length = math.sqrt(dx * dx + dy * dy)
    if length > 0:
        dx = dx / length * radius
        dy = dy / length * radius
    
    x = JOYSTICK_CENTER_X + dx
    y = JOYSTICK_CENTER_Y + dy
    
    # 输出组合方向的调试信息
    keys_str = '+'.join(sorted(current_keys)) if current_keys else 'none'
    if current_keys:
        print(f"[DIR] keys={keys_str} -> target=({int(x)},{int(y)})")
    
    return int(x), int(y)

def update_touch():
    global is_touching, last_x, last_y
    # 主要逻辑在 touch_joystick 线程中处理
    # 此函数仅用于状态更新
    pass

def touch_joystick():
    global is_touching, last_x, last_y, is_sprinting, sprint_end_time
    last_swipe_time = 0  # 上次发送 swipe 的时间
    last_swipe_target = None  # 上次 swipe 的目标位置
    
    while running:
        # 检查疾跑是否过期
        if is_sprinting and time.time() > sprint_end_time:
            is_sprinting = False
            update_touch()
        
        # 如果有按键按住
        if current_keys:
            t_x, t_y = calculate_joystick_position()
            current_time = time.time()
            
            if not is_touching:
                # 首次按下：只发送一次 swipe
                # 从中心滑到目标位置，持续很长时间
                cmd = f"input swipe {JOYSTICK_CENTER_X} {JOYSTICK_CENTER_Y} {t_x} {t_y} 5000"
                send_adb_command(cmd)
                print(f"[TOUCH] DOWN: ({t_x},{t_y})")
                is_touching = True
                last_x = t_x
                last_y = t_y
                last_swipe_time = current_time
                last_swipe_target = (t_x, t_y)
            elif last_swipe_target != (t_x, t_y) or (current_time - last_swipe_time) > 4.5:
                # 只有目标改变或快超时才发送新 swipe
                # 从当前位置滑到新目标（避免回到中心）
                cmd = f"input swipe {last_x} {last_y} {t_x} {t_y} 5000"
                send_adb_command(cmd)
                print(f"[TOUCH] MOVE: ({t_x},{t_y})")
                last_x = t_x
                last_y = t_y
                last_swipe_time = current_time
                last_swipe_target = (t_x, t_y)
        else:
            # 松开
            if is_touching:
                # 发送一个非常短的 swipe 来立即释放
                cmd = f"input swipe {last_x} {last_y} {last_x} {last_y} 10"
                send_adb_command(cmd)
                print(f"[TOUCH] UP: released")
                is_touching = False
                last_x = JOYSTICK_CENTER_X
                last_y = JOYSTICK_CENTER_Y
                last_swipe_target = None
        
        # 每 100ms 检查一次
        time.sleep(0.1)

def check_sprint():
    global is_sprinting, sprint_end_time, w_press_times
    
    now = time.time()
    w_press_times.append(now)
    
    # 只保留最近的按下时间
    w_press_times = [t for t in w_press_times if now - t <= DOUBLE_TAP_THRESHOLD]
    
    # 如果在阈值时间内有2次按下，触发疾跑
    if len(w_press_times) >= 2:
        is_sprinting = True
        sprint_end_time = now + 3.0
        w_press_times.clear()
        print("\n[SPRINT] Activated!")

def on_key_event(event):
    global is_sprinting
    
    key = event.name.lower()
    event_type = event.event_type
    
    # Tab 键触发屏幕测试
    if key == 'tab':
        is_down = event_type == keyboard.KEY_DOWN or event_type == 'down' or event_type == 1
        if is_down:
            run_screen_test()
        return
    
    if key not in ['w', 'a', 's', 'd']:
        return
    
    # 兼容不同版本的keyboard库
    is_down = event_type == keyboard.KEY_DOWN or event_type == 'down' or event_type == 1
    is_up = event_type == keyboard.KEY_UP or event_type == 'up' or event_type == 2
    
    if is_down:
        # 互斥按键：如果互斥键已按下，忽略后按下的按键
        mutex_key = MUTEX_KEYS.get(key)
        if mutex_key in current_keys:
            return
        
        if key not in current_keys:
            current_keys.add(key)
            print(f"[KEY] {key.upper()} | keys: {current_keys}")
            
            if key == 'w':
                check_sprint()
            
            update_touch()
    
    elif is_up:
        if key in current_keys:
            current_keys.discard(key)
            print(f"[KEY] {key.upper()} released | keys: {current_keys}")
            
            if key == 'w':
                is_sprinting = False
            
            update_touch()

# ==================== 屏幕坐标测试 ====================
def run_screen_test():
    """屏幕坐标测试 - 按 Tab 键触发"""
    global running
    
    print("\n" + "=" * 60)
    print("  SCREEN COORDINATE TEST")
    print("  Testing ADB touch commands")
    print("=" * 60)
    
    # 停止摇杆控制
    old_keys = current_keys.copy()
    current_keys.clear()
    update_touch()
    
    cx, cy = JOYSTICK_CENTER_X, JOYSTICK_CENTER_Y
    radius = 200
    
    # 测试 1: input swipe 命令（已知有效）
    print("\n--- Test 1: input swipe (known working) ---")
    print(f"  Swipe Up...", end="", flush=True)
    cmd = f"input swipe {cx} {cy} {cx} {cy-radius} 500"
    print(f"\n    {cmd}")
    send_adb_command(cmd)
    time.sleep(2)
    
    # 测试 2: input touchscreen motionevent 命令
    print("\n--- Test 2: input touchscreen motionevent ---")
    print(f"  DOWN at center...", end="", flush=True)
    send_adb_command(f"input touchscreen motionevent DOWN 0 {cx} {cy}")
    time.sleep(0.5)
    
    print(f"  MOVE Up...", end="", flush=True)
    send_adb_command(f"input touchscreen motionevent MOVE 0 {cx} {cy-radius}")
    time.sleep(2)
    
    print(f"  UP...", end="", flush=True)
    send_adb_command(f"input touchscreen motionevent UP 0 {cx} {cy-radius}")
    time.sleep(1)
    
    # 测试 3: 再次测试 swipe 确认
    print("\n--- Test 3: Second swipe test ---")
    print(f"  Swipe Down...", end="", flush=True)
    cmd = f"input swipe {cx} {cy} {cx} {cy+radius} 500"
    print(f"\n    {cmd}")
    send_adb_command(cmd)
    time.sleep(2)
    
    print("\n" + "=" * 60)
    print("  Test complete!")
    print("  Tell me which tests worked!")
    print("=" * 60 + "\n")
    
    # 恢复按键状态
    if old_keys:
        current_keys.update(old_keys)
        update_touch()

# ==================== 视角控制 ====================
def on_mouse_event(event):
    global is_camera_touching, camera_touch_x, camera_touch_y, last_mouse_x, last_mouse_y, right_button_down
    global accumulated_mouse_dx, accumulated_mouse_dy
    
    if not CAMERA_CONTROL_ENABLED:
        return
    
    if isinstance(event, mouse.ButtonEvent):
        if event.button == 'right':
            if event.event_type == 'down':
                right_button_down = True
                camera_touch_x = CAMERA_START_X
                camera_touch_y = CAMERA_START_Y
                accumulated_mouse_dx = 0
                accumulated_mouse_dy = 0
                send_touch_down(camera_touch_x, camera_touch_y, CAMERA_TOUCH_ID)
                is_camera_touching = True
                last_mouse_x, last_mouse_y = mouse.get_position()
                print("\n[CAM] Right button down")
            else:
                right_button_down = False
                if is_camera_touching:
                    send_touch_up(camera_touch_x, camera_touch_y, CAMERA_TOUCH_ID)
                    is_camera_touching = False
                    print("\n[CAM] Right button up")
        return
    
    if not right_button_down or not isinstance(event, mouse.MoveEvent):
        return
    
    dx = event.x - last_mouse_x
    dy = event.y - last_mouse_y
    last_mouse_x = event.x
    last_mouse_y = event.y
    
    distance = math.sqrt(dx * dx + dy * dy)
    if distance < CAMERA_DEAD_ZONE:
        return
    
    accumulated_mouse_dx += dx
    accumulated_mouse_dy += dy
    
    accumulated_distance = math.sqrt(accumulated_mouse_dx**2 + accumulated_mouse_dy**2)
    
    if accumulated_distance >= CAMERA_STEP_PIXELS:
        target_x = camera_touch_x - int(accumulated_mouse_dx * CAMERA_SENSITIVITY)
        target_y = camera_touch_y + int(accumulated_mouse_dy * CAMERA_SENSITIVITY)
        
        send_touch_move(target_x, target_y, CAMERA_TOUCH_ID)
        camera_touch_x = target_x
        camera_touch_y = target_y
        
        accumulated_mouse_dx = 0
        accumulated_mouse_dy = 0

# ==================== 状态显示 ====================
def show_status():
    while running:
        if current_keys:
            t_x, t_y = calculate_joystick_position()
            keys_str = ','.join(k.upper() for k in sorted(current_keys))
            sprint = " [SPRINT]" if is_sprinting else ""
            status = f"\r[MOV] Keys: {keys_str} | Pos: ({t_x}, {t_y}){sprint}    "
        elif is_touching:
            status = f"\r[TOUCHING] Pos: ({last_x}, {last_y})    "
        else:
            status = f"\r[IDLE] | Center: ({JOYSTICK_CENTER_X}, {JOYSTICK_CENTER_Y})    "
        
        sys.stdout.write(status)
        sys.stdout.flush()
        time.sleep(0.05)

# ==================== 清理 ====================
def cleanup():
    global running, adb_process, is_sprinting, is_camera_touching
    running = False
    is_sprinting = False
    
    if is_touching:
        try:
            send_touch_up(last_x, last_y, JOYSTICK_TOUCH_ID)
        except:
            pass
    
    if is_camera_touching:
        try:
            send_touch_up(camera_touch_x, camera_touch_y, CAMERA_TOUCH_ID)
        except:
            pass
    
    if adb_process is not None:
        try:
            adb_process.stdin.write("exit\n")
            adb_process.stdin.flush()
            adb_process.wait(timeout=1)
        except:
            adb_process.kill()
        adb_process = None

# ==================== 主函数 ====================
def main():
    global last_mouse_x, last_mouse_y
    
    print("\n" + "=" * 60)
    print("  WASD Mobile Joystick Controller")
    print("=" * 60)
    print(f"  Config Screen: {SCREEN_WIDTH}x{SCREEN_HEIGHT}")
    print(f"  Joystick Center: ({JOYSTICK_CENTER_X}, {JOYSTICK_CENTER_Y})")
    print(f"  Move Radius: {JOYSTICK_RADIUS}px")
    print(f"  Camera Start: ({CAMERA_START_X}, {CAMERA_START_Y})")
    print()
    print("  Direction Mapping:")
    for key, (dx, dy) in KEY_DIRECTIONS.items():
        dir_name = "Up" if dy == -1 else "Down" if dy == 1 else "Left" if dx == -1 else "Right"
        print(f"    {key.upper()} -> {dir_name}")
    print("=" * 60)
    print("  W - Forward (Up)")
    print("  S - Backward (Down)")
    print("  A - Left")
    print("  D - Right")
    print("  Double-tap W - Sprint")
    print("  Right Mouse - Camera Control")
    print("  TAB - Screen Coordinate Test")
    print("  ESC - Exit")
    print("=" * 60 + "\n")
    
    # 启动 ADB
    if not start_adb_shell():
        print("Failed to start ADB!")
        return
    
    time.sleep(0.5)
    
    # 获取手机实际分辨率
    print("Getting device resolution...")
    real_w, real_h = get_device_resolution()
    if real_w and real_h:
        print(f"  Device Physical Resolution: {real_w}x{real_h}")
    else:
        print("  Could not get device resolution, using config values.")
    print(f"  Config Resolution: {SCREEN_WIDTH}x{SCREEN_HEIGHT}")
    print(f"  Joystick Center: ({JOYSTICK_CENTER_X}, {JOYSTICK_CENTER_Y})")
    print(f"  Press TAB to test screen coordinates")
    
    # 启动触摸线程
    joystick_thread = threading.Thread(target=touch_joystick, daemon=True)
    joystick_thread.start()
    
    # 启动状态显示线程
    status_thread = threading.Thread(target=show_status, daemon=True)
    status_thread.start()
    
    # 注册键盘钩子
    keyboard.hook(on_key_event)
    
    # 注册鼠标钩子
    if CAMERA_CONTROL_ENABLED:
        last_mouse_x, last_mouse_y = mouse.get_position()
        mouse.hook(on_mouse_event)
    
    print("\nReady! Press WASD to move")
    
    try:
        keyboard.wait('esc')
    finally:
        keyboard.unhook_all()
        if CAMERA_CONTROL_ENABLED:
            mouse.unhook_all()
        cleanup()
    
    print("\nExiting...")

if __name__ == "__main__":
    main()
