extends Node

const ENEMY_SCENE: PackedScene = preload("res://scenes/enemy/enemy.tscn")
const BOSS_STATS: Resource = preload("res://scenes/enemy/boss_stats.tres")
const INVASION_COUNT := 16
const SPAWN_RADIUS := 45.0

var active: bool = false
var invasion_enemies: Array[Node] = []

func _ready() -> void:
  EventBus.wave_timer_tick.connect(_on_wave_timer_tick)
  EventBus.entity_died.connect(_on_entity_died)
  EventBus.tavern_destroyed.connect(_on_tavern_destroyed)

func _on_wave_timer_tick(seconds_remaining: float) -> void:
  if active:
    return
  if seconds_remaining > 0:
    return
  var has_alive_red := false
  for p in get_tree().get_nodes_in_group("red_portal"):
    if is_instance_valid(p) and PortalData.is_alive(p):
      has_alive_red = true
      break
  if not has_alive_red:
    return
  trigger()

func trigger() -> void:
  active = true
  invasion_enemies.clear()
  var tavern: Node = get_tree().get_first_node_in_group("tavern")
  if not tavern:
    active = false
    return
  var world: Node = get_tree().current_scene
  var scale: float = PlayerData.level_scale * 10.0
  for enemy in get_tree().get_nodes_in_group("red_enemies"):
    if is_instance_valid(enemy):
      _convert_to_invasion(enemy, tavern)
  for i in range(INVASION_COUNT):
    var angle: float = randf() * TAU
    var pos := Vector3(cos(angle) * SPAWN_RADIUS, 0, sin(angle) * SPAWN_RADIUS)
    var enemy: Node = ENEMY_SCENE.instantiate()
    enemy.spawn_scale = scale
    world.add_child(enemy)
    enemy.global_position = pos
    _convert_to_invasion(enemy, tavern)
  var boss_angle: float = randf() * TAU
  var boss_pos := Vector3(cos(boss_angle) * SPAWN_RADIUS, 0, sin(boss_angle) * SPAWN_RADIUS)
  var boss: Node = ENEMY_SCENE.instantiate()
  boss.add_to_group("boss")
  boss.stats = BOSS_STATS
  boss.spawn_scale = scale
  world.add_child(boss)
  boss.global_position = boss_pos
  _convert_to_invasion(boss, tavern)
  EventBus.invasion_started.emit(invasion_enemies)

func _convert_to_invasion(enemy: Node, tavern: Node) -> void:
  enemy.add_to_group("invasion")
  var data_source: Node = BossData if enemy.is_in_group("boss") else EnemyData
  data_source.set_stat(enemy, "target", tavern)
  data_source.set_stat(enemy, "state", 1)
  invasion_enemies.append(enemy)

func _on_entity_died(entity: Node) -> void:
  if not active:
    return
  if entity not in invasion_enemies:
    return
  invasion_enemies.erase(entity)
  var alive_count := 0
  for e in invasion_enemies:
    if is_instance_valid(e):
      alive_count += 1
  if alive_count == 0:
    _end_invasion(true)

func _end_invasion(success: bool) -> void:
  active = false
  invasion_enemies.clear()
  EventBus.invasion_ended.emit(success)

func _on_tavern_destroyed() -> void:
  active = false
  EventBus.game_over.emit()
