import json
import os
import random
import time
import pydirectinput

from game_state import parse_game_state
from stuck_handler import StuckHandler

# 定义按键常量
KEY_TAB = '3'
KEY_LOOT = '4'      # 假设你在游戏里设置了互动按键为 F
KEY_ATTACK = '2'    # 假设你的主攻击技能是 1

def load_attack_loop(path):
    """从 JSON 加载攻击循环配置。支持 hp_below_percent/hp_key、mp_below_percent/mp_key（0=不启用）"""
    if not path or not os.path.exists(path):
        return None
    try:
        with open(path, 'r', encoding='utf-8') as f:
            cfg = json.load(f)
        steps = cfg.get('steps') or []
        trigger = float(cfg.get('trigger_chance', 0.3))
        hp_below = int(cfg.get('hp_below_percent', 0)) or 0
        mp_below = int(cfg.get('mp_below_percent', 0)) or 0
        return {
            'trigger_chance': trigger,
            'steps': steps,
            'hp_below_percent': hp_below,
            'hp_key': (cfg.get('hp_key') or '').strip() or None,
            'mp_below_percent': mp_below,
            'mp_key': (cfg.get('mp_key') or '').strip() or None,
        }
    except Exception:
        return None


class AutoBot:
    def __init__(self, waypoints=None, attack_loop_path=None, skinning_wait_sec=None):
        self.last_tab_time = 0
        self.is_running = True
        self.attack_loop_config = load_attack_loop(attack_loop_path)
        self.tab_no_target_count = 0  # 连续按 Tab 仍无目标的次数，满 5 次则转向
        self.stuck_handler = StuckHandler()
        self.target_acquired_time = None  # 本次获得目标的时间（目前仅用于调试/保留接口）
        self.last_turn_end_time = 0  # 最近一次结束 A/D 转向的时间，供卡死检测排除
        self.skinning_wait_sec = float(skinning_wait_sec) if skinning_wait_sec is not None else 1.5

    def execute_disengage_loot(self):
        """从有战斗/目标切换到完全脱战的瞬间，执行拾取 + 剥皮。"""
        try:
            # 拾取
            pydirectinput.press(KEY_LOOT)
            time.sleep(0.5)
            # 剥皮
            pydirectinput.press(KEY_LOOT)
            time.sleep(self.skinning_wait_sec)
        except Exception:
            pass
        
    def execute_combat_logic(self, state):
        if self.attack_loop_config:
            cfg = self.attack_loop_config
            if random.random() >= cfg['trigger_chance']:
                return
            hp = state.get('hp')
            if hp is not None and cfg.get('hp_below_percent') and cfg.get('hp_key') and hp < cfg['hp_below_percent']:
                pydirectinput.press(cfg['hp_key'])
                time.sleep(0.2)
            mp = state.get('mp')
            if mp is not None and cfg.get('mp_below_percent') and cfg.get('mp_key') and mp < cfg['mp_below_percent']:
                pydirectinput.press(cfg['mp_key'])
                time.sleep(0.2)

            # 每次攻击前选中目标
            pydirectinput.press(KEY_LOOT)
            for step in cfg['steps']:
                key = step.get('key') or KEY_ATTACK
                delay = float(step.get('delay', 0.5))
                pydirectinput.press(key)
                time.sleep(delay)
            return
        # 默认：模拟手动按键的节奏
        if random.random() < 0.3:
            pydirectinput.press(KEY_ATTACK)
            time.sleep(0.5)

    def execute_logic(self, state):
        current_time = time.time()

        # --- 场景 1：没有目标，按 Tab 选怪；连续 5 次无目标则随机左/右转再重试 ---
        if not state['target']:
            self.execute_disengage_loot()
            self.target_acquired_time = None  # 脱战/无目标时清零
            self.stuck_handler.reset()  # 避免脱战期间保留上次站桩的计时，导致重新选到目标立刻误判卡死
            self.tab_no_target_count = min(self.tab_no_target_count, 5)
            if self.tab_no_target_count >= 5:
                # 随机左转或右转一段时间，再重新获取目标
                turn_key = random.choice(["a", "d"])  # a=左转, d=右转
                pydirectinput.keyDown(turn_key)
                time.sleep(random.uniform(0.3, 0.6))
                pydirectinput.keyUp(turn_key)
                self.tab_no_target_count = 0
                self.last_tab_time = current_time
                self.last_turn_end_time = current_time  # 供卡死检测排除刚转向的一小段时间
            elif current_time - self.last_tab_time > random.uniform(0.5, 1.2):
                pydirectinput.press(KEY_TAB)
                self.last_tab_time = current_time
                self.tab_no_target_count += 1
        else:
            self.tab_no_target_count = 0  # 有目标时清零
            # 跑向怪阶段的卡死检测：只在目标血量为 100% 时认为是在“刚刚开怪、接近怪物”，避免残血目标也触发跑向怪卡死逻辑
            target_hp = state.get('target_hp')
            if target_hp >= 100:
                try:
                    if self.stuck_handler.check_stuck(state, self.last_turn_end_time):
                        print(">>> [自动打怪] 可能卡住障碍物，执行脱困")
                        self.stuck_handler.resolve_stuck()
                        self.stuck_handler.reset()
                        return
                except Exception:
                    pass

        # --- 场景 2：有目标且不在战斗中，按交互键 ---
        if state['target'] and not state['combat']:
            if random.random() < 0.3:  # 只有 30% 的循环频率触发按键，模拟真人频率
                pydirectinput.press(KEY_LOOT)

        # --- 场景 3：有目标且在战斗中，自动按技能 ---
        elif state['target'] and state['combat']:
            self.execute_combat_logic(state)

        # --- 场景 3：脱战且有可拾取物（需要你在 Lua 增加拾取位，见下文） ---
        # if not state['in_combat'] and state['has_loot']:
        #     pydirectinput.press(KEY_LOOT)

# 在 main 循环中使用：从 game_state 获取 state
if __name__ == "__main__":
    bot = AutoBot()
    try:
        while True:
            state = parse_game_state()
            if state:
                target_hp = state.get('target_hp')
                if target_hp is not None:
                    hp_part = f"血量:{state['hp']}% 目标血:{target_hp}% | 法力:{state['mp']}% | "
                else:
                    hp_part = f"血量:{state['hp']}% | 法力:{state['mp']}% | "
                print(
                    f"\r[状态] {hp_part}"
                    f"战斗:{'YES' if state['combat'] else 'NO '} | "
                    f"目标:{'YES' if state['target'] else 'NO '}",
                    end=""
                )
                bot.execute_logic(state)
            time.sleep(0.1)
    except KeyboardInterrupt:
        print("\n已停止。")