extends Node2D
class_name Game

@onready var health_bar: HealthBar = $HealthBar
@onready var overlay: CanvasLayer = $Overlay
@onready var transition: Transition = $Overlay/Transition
@onready var player_spawn: PlayerSpawnZone = $PlayerSpawnZone
@onready var spawn_timer: Timer = $Timer
@onready var ui_root: Control = $UI/Root
@onready var wave_label: Label = $UI/Root/WaveLabel
@onready var phase_label: Label = $UI/Root/PhaseLabel
@onready var next_phase_button: Button = $UI/Root/NextPhaseButton

@onready var combat_start_sound: AudioStreamPlayer = $Sounds/CombatStartSound

@onready var main_menu: PackedScene = load("res://screens/main_menu.tscn")
@onready var bot_scene: PackedScene = load("res://assets/scenes/bot.tscn")
@onready var game_over_scene: PackedScene = load("res://assets/scenes/game_over.tscn")
@onready var victory_scene: PackedScene = load("res://assets/scenes/victory.tscn")

@onready var left_enemy_label: Label = $UI/Root/LeftEnemyLabel
@onready var right_enemy_label: Label = $UI/Root/RightEnemyLabel
@onready var top_enemy_label: Label = $UI/Root/TopEnemyLabel

@onready var spawn_points: Array[Marker2D] = [
	$EnemySpawns/EnemySpawn_Left,
	$EnemySpawns/EnemySpawn_Right,
	$EnemySpawns/EnemySpawn_Top,
]
@onready var enemy_labels: Array[Label] = [
	$UI/Root/LeftEnemyLabel,
	$UI/Root/RightEnemyLabel,
	$UI/Root/TopEnemyLabel,
]

enum Phase {
	PHASE_SETUP,
	PHASE_COMBAT,
	PHASE_LOOT,
}

enum Loot {
	LOOT_SURVIVOR,
	LOOT_HEAL,
	LOOT_LOWER_COOLDOWN,
}

const RELOAD_TIME: float = 4.0
static var reload_time: float = RELOAD_TIME # seconds
static var max_ammo: int = 1 # shots
static var base_accuracy: float = 0.33 # percent

var phase: Phase = Phase.PHASE_SETUP:
	set(new_value):
		phase = new_value
		match new_value:
			Phase.PHASE_SETUP:
				phase_label.text = "PHASE: SETUP"
			Phase.PHASE_COMBAT:
				phase_label.text = "PHASE: COMBAT"
			Phase.PHASE_LOOT:
				phase_label.text = "PHASE: LOOT"

var waves_completed: int = 0:
	set(new_value):
		waves_completed = new_value
		wave_label.text = "WAVE: %d" % (new_value + 1)

func update_enemy_labels() -> void:
	for n in 3:
		var enemies = spawn_points[n].get_child_count()
		enemy_labels[n].text = str(enemies)

func set_enemy_label_visible(value: bool) -> void:
	for label in enemy_labels:
		label.visible = value

func _ready() -> void:
	Game.reload_time = RELOAD_TIME # seconds
	Game.max_ammo = 1 # shots
	Game.base_accuracy = 0.33 # percent
	waves_completed = 0
	phase = Phase.PHASE_SETUP
	overlay.visible = true
	start_setup()
	player_spawn.add_survivor()
	transition.slide_out()
	await transition.game_fully_visible

func _process(_delta: float) -> void:
	if Input.is_action_pressed("ui_cancel"):
		go_to_main_menu()
	if phase == Phase.PHASE_COMBAT:
		if get_foes().is_empty() and health_bar.health != 0:
			end_combat()

func go_to_main_menu() -> void:
	var tree = get_tree()
	transition.text = ""
	tree.paused = true
	transition.slide_in()
	await transition.game_fully_hidden
	tree.change_scene_to_packed(main_menu)
	tree.paused = false

func spawn_bot(spawn: Marker2D, index: int) -> void:
	var bot: Bot = bot_scene.instantiate()
	bot.name = "Bot #%d" % (index + 1)
	bot.speed += waves_completed
	bot.visible = false
	spawn.add_child(bot)
	bot.position = Vector2.ZERO

func get_foes() -> Array[Area2D]:
	var foes: Array[Area2D] = []
	foes.assign(get_tree().get_nodes_in_group("foe"))
	return foes

func get_survivors() -> Array[Area2D]:
	var survivors: Array[Area2D] = []
	survivors.assign(get_tree().get_nodes_in_group("survivor"))
	return survivors

func get_waiting_foes() -> Array[Area2D]:
	return get_foes().filter(func (foe): return not foe.visible)

func get_active_foes() -> Array[Area2D]:
	return get_foes().filter(func (foe): return foe.visible)
	
func activate_foe() -> void:
	var foes = get_waiting_foes()
	if not foes.is_empty():
		foes.pick_random().visible = true

func reset_survivors() -> void:
	var survivors = get_survivors()
	#for survivor in survivors:
	#	survivor.reparent(self)
	for survivor in survivors:
		#player_spawn.drop(survivor)
		#survivor.position = Vector2.ZERO
		#survivor.rotation = 0.0
		survivor.ammo = Game.max_ammo

func _on_timer_timeout() -> void:
	activate_foe()

func base_hit() -> void:
	health_bar.health -= 1
	if health_bar.health == 0:
		await game_over()

func game_over() -> void:
	spawn_timer.stop()
	var foes = get_tree().get_nodes_in_group("foe")
	for foe in foes:
		foe.queue_free()
	
	var gos: GameOver = game_over_scene.instantiate()
	gos.message = "YOU DIED AFTER\nCOMPLETING %d WAVES!" % waves_completed
	ui_root.add_child(gos)
	await gos.closed
	await go_to_main_menu()

func _on_base_area_entered(area: Area2D) -> void:
	if area.is_in_group("foe") || area.is_in_group("foe_weapons"):
		base_hit()

func start_setup() -> void:
	for n in (waves_completed + 1):
		var spawner = spawn_points.pick_random()
		spawn_bot(spawner, n)
	update_enemy_labels()
	set_enemy_label_visible(true)

func start_combat() -> void:
	set_enemy_label_visible(false)
	GlobalInput.dragging_disabled = true
	spawn_timer.wait_time = lerpf(3.5, 0.5, minf(float(waves_completed)/20.0, 1.0))
	spawn_timer.start()
	combat_start_sound.play()
	activate_foe()

const LOOT_SURVIVOR: String = "+1 SURVIVOR"
const LOOT_HEALTH: String = "+3 HEALTH"
const LOOT_AMMO: String = "BIGGER MAGAZINES"
const LOOT_RELOAD_TIME: String = "FASTER RELOADING"
const LOOT_ACCURACY: String = "HIGHER ACCURACY"
const LOOTS: Array[String] = [LOOT_SURVIVOR, LOOT_HEALTH, LOOT_AMMO, LOOT_RELOAD_TIME, LOOT_ACCURACY]

func end_combat() -> void:
	phase = Phase.PHASE_LOOT
	spawn_timer.stop()
	await get_tree().create_timer(1.5).timeout
	var vs: Victory = victory_scene.instantiate()
	ui_root.add_child(vs)
	var loots: Array[String] = []
	loots.assign(LOOTS)
	if get_survivors().size() >= 6: # this is, so the player has a reason to move survivors even later
		loots.erase(LOOT_SURVIVOR)
	loots.shuffle()
	vs.set_loot_options(loots[0], loots[1], loots[2])
	await vs.loot_selected
	var loot: String = loots[vs.selection]
	print("selected loot: " + str(loot))
	var next_wave = waves_completed + 2
	await transition.transition("WAVE %d" % next_wave, func ():
		self.waves_completed += 1
		self.phase = Phase.PHASE_SETUP
		self.next_phase_button.disabled = false
		match loot:
			LOOT_SURVIVOR:
				self.player_spawn.add_survivor()
			LOOT_HEALTH:
				self.health_bar.health += 3
			LOOT_RELOAD_TIME:
				Game.reload_time *= 0.9
			LOOT_AMMO:
				Game.max_ammo += 1
			LOOT_ACCURACY:
				Game.base_accuracy += 0.1
		self.reset_survivors()
		self.start_setup()
	)
	GlobalInput.dragging_disabled = false

func _on_next_phase_button_pressed() -> void:
	match phase:
		Phase.PHASE_SETUP:
			phase = Phase.PHASE_COMBAT
			next_phase_button.disabled = true
			start_combat()
		Phase.PHASE_COMBAT:
			pass # this should not happen
		Phase.PHASE_LOOT:
			pass # this should not happen
