## StatusManager — 状态效果管理（Autoload: StatusManager）
## 权威来源：combat_mechanics_depth.md §3.2.5、implementation_plan.md §2.4
extends Node

const STATUS_BATCH_LIMIT: int = 500

var _active_statuses: Array = []  # Array[StatusInstance]
var _physics_frame:   int   = 0

func _physics_process(delta: float) -> void:
	_physics_frame += 1
	var use_batch: bool = _active_statuses.size() > STATUS_BATCH_LIMIT
	var batch_parity: int = _physics_frame % 2

	var i: int = _active_statuses.size() - 1
	while i >= 0:
		var inst: StatusInstance = _active_statuses[i]
		if use_batch and (inst.entity_id % 2) != batch_parity:
			i -= 1
			continue

		inst.remaining_duration -= delta
		inst.tick_accumulator   += delta

		if inst.type_def and not inst.type_def.is_combo_tracker and inst.type_def.dot_damage_per_tick > 0.0:
			var interval: float = max(0.001, inst.type_def.tick_interval)
			while inst.tick_accumulator >= interval:
				inst.tick_accumulator -= interval
				_apply_dot_tick(inst)

		if inst.remaining_duration <= 0.0:
			_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
			_active_statuses.pop_back()
		i -= 1

## 施加状态；duration < 0 时使用 StatusTypeDef 默认 duration
func apply(entity_id: int, status_type_id: int, stacks: int = 1, duration: float = -1.0, owner_id: int = -1) -> void:
	var typedef: StatusTypeDef = StatusRegistry.get_type(status_type_id)
	if typedef == null:
		push_warning("StatusManager.apply: 未知 status_id=%d" % status_type_id)
		return

	var dur: float = typedef.duration if duration < 0.0 else duration
	var existing_idx: int = _find(entity_id, status_type_id)

	if existing_idx >= 0:
		var inst: StatusInstance = _active_statuses[existing_idx]
		match typedef.stack_mode:
			StatusTypeDef.StackMode.REFRESH:
				inst.remaining_duration = dur
				inst.stacks = max(inst.stacks, stacks)
			StatusTypeDef.StackMode.INTENSITY:
				var cap: int = typedef.max_stacks if typedef.max_stacks > 0 else 9999
				inst.stacks = min(inst.stacks + stacks, cap)
				inst.remaining_duration = dur
			StatusTypeDef.StackMode.INDEPENDENT:
				pass  # 独立实例：追加新条目
		if typedef.stack_mode != StatusTypeDef.StackMode.INDEPENDENT:
			EventBus.emit(EventID.STATUS_APPLIED, {
				"target_id": entity_id, "status_type": status_type_id, "stacks": inst.stacks
			})
			return

	var inst_new := StatusInstance.new()
	inst_new.setup(entity_id, typedef, stacks, dur, owner_id)
	_active_statuses.append(inst_new)
	EventBus.emit(EventID.STATUS_APPLIED, {
		"target_id": entity_id, "status_type": status_type_id, "stacks": inst_new.stacks
	})

func get_stacks(entity_id: int, status_type_id: int) -> int:
	var idx: int = _find(entity_id, status_type_id)
	if idx < 0:
		return 0
	return _active_statuses[idx].stacks

func has_status(entity_id: int, status_type_id: int) -> bool:
	return _find(entity_id, status_type_id) >= 0

func remove_all_for_entity(entity_id: int) -> void:
	var i: int = _active_statuses.size() - 1
	while i >= 0:
		if _active_statuses[i].entity_id == entity_id:
			_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
			_active_statuses.pop_back()
		i -= 1

func remove_source(owner_id: int) -> void:
	var i: int = _active_statuses.size() - 1
	while i >= 0:
		if _active_statuses[i].owner_id == owner_id:
			_active_statuses[i] = _active_statuses[_active_statuses.size() - 1]
			_active_statuses.pop_back()
		i -= 1

func get_active_count() -> int:
	return _active_statuses.size()

func reset() -> void:
	_active_statuses.clear()
	_physics_frame = 0

func _find(entity_id: int, status_type_id: int) -> int:
	for i in _active_statuses.size():
		var inst: StatusInstance = _active_statuses[i]
		if inst.entity_id == entity_id and inst.status_type_id == status_type_id:
			return i
	return -1

func _apply_dot_tick(inst: StatusInstance) -> void:
	if not EnemyManager.has_entity(inst.entity_id):
		return
	var dmg: float = inst.type_def.dot_damage_per_tick * float(inst.stacks)
	if dmg <= 0.0:
		return
	EnemyManager.apply_damage(inst.entity_id, dmg, inst.owner_id, false)

func _swap_and_pop(idx: int) -> void:
	var last: int = _active_statuses.size() - 1
	if idx != last:
		_active_statuses[idx] = _active_statuses[last]
	_active_statuses.pop_back()
