## PlayerManager — 玩家管理 Autoload
## S0：WASD 移动 + 位置查询
## S1：自动施法
## S4：停步蓄力 / 冲刺边沿检测（P6-N69、P6-N36）
extends Node

const MOVE_SPEED:          float = 200.0
const MOVE_THRESHOLD_NORM: float = 0.1
const CHARGE_TRIGGER_TIME: float = 1.5

var _position:  Vector2 = Vector2.ZERO
var _velocity:  Vector2 = Vector2.ZERO
var _player_node: Node2D = null

var _equipped_core:     CoreDefinition = null
var _equipped_compiled: CompiledDeck  = null
var _cast_timer:        float = 0.0
var _cast_interval:     float = 0.5

var _is_moving:         bool  = false
var _stationary_time:   float = 0.0
var _charge_triggered:  bool  = false
var _last_dash_time:    float = -999.0

var kill_count: int = 0

func _ready() -> void:
	EventBus.subscribe(EventID.ENEMY_KILLED, _on_enemy_killed)

func _physics_process(delta: float) -> void:
	PlayerStats.regen_mana(delta)
	PlayerStats.mana_heat = maxf(0.0, PlayerStats.mana_heat - SettingsManager.mana_heat_decay() * delta)
	_handle_movement(delta)
	_handle_charge_state(delta)
	_handle_auto_cast(delta)

func _handle_movement(delta: float) -> void:
	var dir := Vector2(
		Input.get_axis("ui_left",  "ui_right"),
		Input.get_axis("ui_up",    "ui_down")
	)
	_is_moving = dir.length() > MOVE_THRESHOLD_NORM
	if _is_moving:
		dir = dir.normalized()
		_velocity = dir * MOVE_SPEED
	else:
		_velocity = Vector2.ZERO
	_position += _velocity * delta
	if _player_node:
		_player_node.global_position = _position

func _handle_charge_state(delta: float) -> void:
	if Input.is_action_just_pressed("ui_accept"):
		_last_dash_time = Time.get_ticks_msec() / 1000.0
		EventBus.emit(EventID.DASH_TRIGGERED, {
			"caster_id": 0,
			"stationary_time": _stationary_time,
		})
		_stationary_time  = 0.0
		_charge_triggered = false
		return

	if _is_moving:
		if _stationary_time > 0.0:
			_stationary_time  = 0.0
			_charge_triggered = false
			EventBus.emit(EventID.CHARGE_STATE_CHANGED, {"caster_id": 0, "progress": 0.0})
	else:
		_stationary_time += delta
		if _stationary_time >= 0.3:
			var prog: float = clampf(_stationary_time / CHARGE_TRIGGER_TIME, 0.0, 1.0)
			EventBus.emit(EventID.CHARGE_STATE_CHANGED, {"caster_id": 0, "progress": prog})
		if _stationary_time >= CHARGE_TRIGGER_TIME and not _charge_triggered:
			_charge_triggered = true
			EventBus.emit(EventID.CHARGE_FIRED, {"caster_id": 0})

func _handle_auto_cast(delta: float) -> void:
	if _equipped_compiled == null or _equipped_compiled.is_empty():
		return
	_cast_timer -= delta
	if _cast_timer <= 0.0:
		_cast_timer = _cast_interval
		SpellEvaluator.execute_compiled(_equipped_compiled, 0, _position)

func equip_wand(core: CoreDefinition, compiled: CompiledDeck) -> void:
	_equipped_core     = core
	_equipped_compiled = compiled
	_cast_interval     = core.cast_interval if core else 0.5
	_cast_timer        = 0.0
	if core:
		PlayerStats.set_mana_pool(core.base_mana_max, core.base_mana_regen)
	else:
		PlayerStats.set_mana_pool(100.0, 5.0)
	PlayerStats.mana_heat = 0.0

func get_position() -> Vector2:
	return _position

func get_velocity() -> Vector2:
	return _velocity

func get_stationary_time() -> float:
	return _stationary_time

func is_charge_triggered() -> bool:
	return _charge_triggered

func set_player_node(node: Node2D) -> void:
	_player_node = node
	if node:
		_position = node.global_position

func _on_enemy_killed(_payload: Dictionary) -> void:
	kill_count += 1

func reset() -> void:
	_position          = Vector2.ZERO
	_velocity          = Vector2.ZERO
	_player_node       = null
	_equipped_compiled = null
	_equipped_core     = null
	_cast_timer        = 0.0
	_is_moving         = false
	_stationary_time   = 0.0
	_charge_triggered  = false
	kill_count         = 0
