extends Node

const PORTAL_SCENE: PackedScene = preload("res://scenes/portal/portal.tscn")
const GATE_SCENE: PackedScene = preload("res://scenes/portal/gate.tscn")
const RED_PORTAL_STATS: Resource = preload("res://scenes/portal/red_portal_stats.tres")
const MAX_NORMAL_PORTALS := 3
const MIN_DISTANCE := 20.0
const MAX_DISTANCE := 40.0
const RESPAWN_DELAY := 1.0

var portals: Array[Node] = []

func _ready() -> void:
  EventBus.portal_defeated.connect(_on_portal_defeated)
  EventBus.wave_started.connect(_on_wave_started)
  if PlayerData.portal_position != Vector3.ZERO and not PlayerData.dungeon_cleared:
    call_deferred("_restore_gate")
  else:
    if PlayerData.dungeon_cleared:
      PlayerData.clear_cache()
    call_deferred("_ensure_portals")

func _restore_gate() -> void:
  var gate: Node3D = GATE_SCENE.instantiate()
  get_parent().add_child(gate)
  gate.global_position = PlayerData.portal_position

func _ensure_portals() -> void:
  _cleanup_dead()
  while portals.size() < MAX_NORMAL_PORTALS:
    _spawn_portal()

func _on_portal_defeated(portal: Node) -> void:
  if portal.is_in_group("red_portal"):
    return
  portals.erase(portal)
  await get_tree().create_timer(RESPAWN_DELAY).timeout
  _ensure_portals()

func _on_wave_started(_wave_number: int) -> void:
  _spawn_red_portal()

func _spawn_red_portal() -> void:
  for p in get_tree().get_nodes_in_group("red_portal"):
    if is_instance_valid(p):
      return
  var angle: float = randf() * TAU
  var distance: float = randf_range(MIN_DISTANCE, MAX_DISTANCE)
  var pos := Vector3(cos(angle) * distance, 0, sin(angle) * distance)
  var portal: Node3D = PORTAL_SCENE.instantiate()
  portal.stats = RED_PORTAL_STATS
  get_parent().add_child(portal)
  portal.global_position = pos

func _spawn_portal() -> void:
  var angle: float = randf() * TAU
  var distance: float = randf_range(MIN_DISTANCE, MAX_DISTANCE)
  var pos := Vector3(cos(angle) * distance, 0, sin(angle) * distance)
  var portal: Node3D = PORTAL_SCENE.instantiate()
  get_parent().add_child(portal)
  portal.global_position = pos
  portals.append(portal)

func _cleanup_dead() -> void:
  var valid: Array[Node] = []
  for p in portals:
    if is_instance_valid(p):
      valid.append(p)
  portals = valid
