extends Node2D

@onready var score_label := $Label
@onready var satellites := $Satellites
@onready var astronauts := $astronauts
@onready var debris := $debris
@onready var oxygen := $TextureProgressBar
@onready var debris_timer := $DebrisTimer
@onready var level_5_timer := $Level5Timer
@onready var cadavers := $Cadavers
@onready var shooting_stars := $ShootingStars
@onready var shooting_star_timer := $ShootingStartTimer

var astro_scene := load("res://actors/astronaut.tscn")
var equip_scene := load("res://equipment/equipment.tscn")
var satellite_scenes := [load("res://actors/satellites/classic_satellite.tscn")]
var debris_scenes := [load("res://utils/slow_debris.tscn")]
var shooting_star_scene := [load("res://utils/shooting_start.tscn")]

const y_position_range := Vector2(70, 220)
const y_direction_range := Vector2(-0.25, 0.25)

const spawn_limits_x := Vector2(170, 470)
const spawn_limits_y := Vector2(300, 355)

var debris_chance := 0.0

var shooting_star_time_range := Vector2(2.0, 15.0)


### 	 ACCESSORS 	 ###






### 	 BUILT-IN 	 ###

func _ready() -> void:
	EVENTS.money_earned.connect(_on_money_earned)
	EVENTS.satellite_clean.connect(_on_satellite_clean)
	EVENTS.cadaver_spawned.connect(_on_cadaver_spawned)
	init_crew()
	_on_money_earned(0)
	if GLOBALS.level > 5:
		satellite_scenes.append(load("res://actors/satellites/medium_satellite.tscn"))
	if GLOBALS.level > 15:
		satellite_scenes.append(load("res://actors/satellites/medium_satellite.tscn"))
	if GLOBALS.level > 25:
		GLOBALS.dirt_range = Vector2(2,2)
	elif GLOBALS.level > 20:
		GLOBALS.dirt_range = Vector2(1,2)
	elif GLOBALS.level > 15:
		GLOBALS.dirt_range = Vector2(0,2)
	elif GLOBALS.level > 10:
		GLOBALS.dirt_range = Vector2(-1,2)
	elif GLOBALS.level > 5:
		GLOBALS.dirt_range = Vector2(-1,1)
	generate_satellites()
	debris_chance = max(0.02 * (GLOBALS.level-5), 0.0)
	if debris_chance > 0:
		debris_timer.start()
	if GLOBALS.level == 5:
		level_5_timer.start()
	shooting_star_timer.start(randf_range(shooting_star_time_range.x, shooting_star_time_range.y))


### 	 VIRTUAL 	 ###





### 	 LOGIC 	 ###

func init_crew() -> void:
	var astro : Astronaut = null
	var equip : Equipment = null
	for member in GLOBALS.crew:
		astro = astro_scene.instantiate()
		astro.call_sign = member.call_sign
		astro.anim_type = member.anim_type
		for eq in member.equipment:
			equip = equip_scene.instantiate()
			equip.type = eq.type
			equip.level = eq.level
			equip.visible = false
		astro.global_position = Vector2(randf_range(spawn_limits_x.x, spawn_limits_x.y),randf_range(spawn_limits_y.x, spawn_limits_y.y))
		astronauts.add_child(astro)


func generate_satellites() -> void:
	var new_sat : Satellite = null
	for i in range(min(GLOBALS.level, 20)):
		new_sat = satellite_scenes.pick_random().instantiate()
		if randi_range(0,1):
			new_sat.global_position.x = -80
		else:
			new_sat.global_position.x = 720
			new_sat.speed *= -1
		new_sat.direction.y = randf_range(y_direction_range.x, y_direction_range.y)
		new_sat.direction = new_sat.direction.normalized()
		new_sat.speed += new_sat.speed * randf_range(0.0, GLOBALS.level)
		new_sat.global_position.y = randf_range(y_position_range.x, y_position_range.y)
		new_sat.wait_time = randf_range(0.0, GLOBALS.level)
		satellites.add_child(new_sat)


func generate_debris() -> void:
	var new_sat : Debris = null
	new_sat = debris_scenes.pick_random().instantiate()
	if randi_range(0,1):
		new_sat.global_position.x = 0
		new_sat.direction *= -1
	else:
		new_sat.global_position.x = 640
	new_sat.direction.y = randf_range(y_direction_range.x, y_direction_range.y) * 2
	new_sat.set_direction(new_sat.direction.normalized())
	new_sat.speed += randf_range(0.0, GLOBALS.level)
	new_sat.global_position.y = randf_range(y_position_range.x, y_position_range.y)
	debris.add_child(new_sat)


func level_done() -> void:
	if GLOBALS.score < 0:
		get_tree().change_scene_to_file("res://scenes/node_2d.tscn")
	else:
		GLOBALS.level += 1
		get_tree().change_scene_to_file("res://scenes/lobby.tscn")


func check_astros() -> void:
	if satellites.get_child_count() == 0 or astronauts.get_child_count() == 0:
		level_done()

### 	 SIGNAL-RESPONSE 	 ###

func _on_money_earned(amount) -> void:
	GLOBALS.score += amount
	score_label.text = str(GLOBALS.score)


func _on_satellite_clean() -> void:
	var clean = true
	for satellite in satellites.get_children():
		if !satellite.clean:
			clean = false
	if clean:
		level_done()


func _on_astro_limits_area_entered(area: Area2D) -> void:
	area.owner.leave_satellite()
	if area.owner.global_position.x < 10:
		area.owner.global_position.x = 10
	elif area.owner.global_position.x > 630:
		area.owner.global_position.x = 630
	if area.owner.global_position.y < 10:
		area.owner.global_position.y = 10
	elif area.owner.global_position.y > 350:
		area.owner.global_position.y = 350
	area.owner.set_state("Idle")


func _on_timer_timeout() -> void:
	oxygen.value -= 1
	check_astros()
	if oxygen.value < 1:
		level_done()


func _on_debris_timer_timeout() -> void:
	while randf() < debris_chance:
		generate_debris()


func _on_level_5_timer_timeout() -> void:
	generate_debris()


func _on_destroyer_area_2d_body_entered(body: Node2D) -> void:
	body.queue_free()


func _on_destroyer_area_2d_area_entered(area: Area2D) -> void:
	area.queue_free()


func _on_cadaver_spawned(cadaver) -> void:
	cadavers.call_deferred("add_child",cadaver)


func _on_shooting_start_timer_timeout() -> void:
	var new_star = shooting_star_scene.pick_random().instantiate()
	new_star.global_position.x = randi_range(0, 640)
	new_star.global_position.y = randi_range(0, 360)
	shooting_stars.add_child(new_star)
	shooting_star_timer.start(randf_range(shooting_star_time_range.x, shooting_star_time_range.y))
