extends Node

var tracker: Node
var config: AggroConfig
var last_damage_time: Dictionary = {}

func process(delta: float) -> void:
  _update_combat_timers(delta)
  for enemy in tracker.aggro_tables.keys():
    if not is_instance_valid(enemy):
      tracker.aggro_tables.erase(enemy)
      tracker.players_in_range.erase(enemy)
      continue
    _decay_aggro(enemy, delta)
    tracker.update_target(enemy)

func _update_combat_timers(delta: float) -> void:
  for player in last_damage_time.keys():
    if not is_instance_valid(player):
      last_damage_time.erase(player)
    else:
      last_damage_time[player] += delta

func _decay_aggro(enemy: Node, delta: float) -> void:
  var table: Dictionary = tracker.aggro_tables[enemy]
  var data_source: Node = tracker._get_data_source(enemy)
  var aggro_decay: float = 1.0
  if data_source:
    var base: EnemyStats = data_source.get_base(enemy)
    if base:
      aggro_decay = base.aggro_decay
  for player in table.keys():
    if is_in_combat(player):
      continue
    var time_since_combat: float = last_damage_time.get(player, config.combat_timeout) - config.combat_timeout
    var decay: float = aggro_decay * delta
    decay += _exponential_decay(table[player], time_since_combat, delta)
    table[player] -= decay
    if table[player] <= 0:
      table.erase(player)

func reset_combat_timer(player: Node) -> void:
  last_damage_time[player] = 0.0

func is_in_combat(player: Node) -> bool:
  if tracker.is_player_in_any_range(player):
    return true
  return last_damage_time.get(player, config.combat_timeout + 1.0) < config.combat_timeout

func _exponential_decay(aggro: float, time_outside: float, delta: float) -> float:
  if time_outside <= 0:
    return 0.0
  return aggro * config.exponential_decay_factor * pow(2, time_outside) * delta

func spread_aggro(source: Node, attacker: Node, amount: float) -> void:
  if not is_instance_valid(source):
    return
  var radius: float = tracker.get_alert_radius(source)
  for enemy in tracker.get_enemies_in_radius(source, radius):
    tracker.add_aggro(enemy, attacker, amount)

func alert_nearby(enemy: Node, target: Node) -> void:
  var radius: float = tracker.get_alert_radius(enemy)
  for other in tracker.get_enemies_in_radius(enemy, radius):
    var data_source: Node = tracker._get_data_source(other)
    if data_source and data_source.get_stat(other, "state") == 0:
      tracker.add_aggro(other, target, 1.0)
      data_source.set_stat(other, "target", target)
      data_source.set_stat(other, "state", 1)
      EventBus.enemy_engaged.emit(other, target)

func erase_entity(entity: Node) -> void:
  last_damage_time.erase(entity)
