extends Node3D
class_name EnemySpawner

## Spawns enemies in waves around the arena edge
## Server-authoritative spawning with multiplayer sync

signal wave_started(wave_number: int)
signal wave_completed(wave_number: int)
signal enemy_spawned(enemy: Node)
signal all_enemies_defeated()

## Spawn configuration
@export_category("Spawn Settings")
@export var spawn_radius: float = 20.0  ## Distance from spawner center to spawn enemies
@export var spawn_height: float = 0.5   ## Height above ground to spawn
@export var enemies_per_wave: int = 3   ## How many enemies spawn per wave
@export var auto_start_next_wave: bool = false  ## Auto-start next wave when all defeated
@export var wave_delay: float = 5.0     ## Delay before next wave auto-starts

@export_category("Timed Waves")
@export var auto_waves: bool = true       ## Spawn a fresh wave on a repeating timer
@export var wave_interval: float = 15.0   ## Seconds between timed waves
@export var first_wave_delay: float = 3.0 ## Delay before the very first timed wave

@export_category("Enemy Pool")
@export var enemy_scenes: Array[PackedScene] = []  ## List of enemy scenes to spawn from

## Wave tracking
var current_wave: int = 0
var active_enemies: Array[Node] = []
var _wave_delay_timer: float = 0.0
var _waiting_for_next_wave: bool = false
var _enemy_id_counter: int = 0
var _auto_waves_active: bool = false
var _auto_wave_timer: float = 0.0

## Debug visualization
@export var show_spawn_radius: bool = false  ## Show spawn radius circle in game
var _debug_circle: MeshInstance3D = null

func _ready():
	print("[EnemySpawner] Ready. Server: ", multiplayer.is_server())
	_create_debug_circle()

## Begin spawning waves automatically on a timer (server only)
func start_auto_waves():
	if not multiplayer.is_server() or not auto_waves:
		return
	_auto_waves_active = true
	_auto_wave_timer = first_wave_delay
	print("[EnemySpawner] Auto waves enabled - first wave in ", first_wave_delay, "s, then every ", wave_interval, "s")

## Stop the timed-wave loop
func stop_auto_waves():
	_auto_waves_active = false

## Start a new wave
func start_wave():
	if not multiplayer.is_server():
		return

	if not is_inside_tree():
		push_error("[EnemySpawner] Cannot start wave - spawner not in scene tree!")
		return

	if enemy_scenes.is_empty():
		push_error("[EnemySpawner] No enemy scenes configured!")
		return

	current_wave += 1
	print("[EnemySpawner] Starting wave ", current_wave)
	wave_started.emit(current_wave)

	# Broadcast wave number to every peer's GameState (for HUD + run stats)
	GameState.server_sync_wave(current_wave)

	# Spawn enemies
	for i in range(enemies_per_wave):
		_spawn_enemy(i, enemies_per_wave)

## Spawn a single enemy at a position around the circle
func _spawn_enemy(index: int, total: int):
	if not multiplayer.is_server():
		return

	if not is_inside_tree():
		push_error("[EnemySpawner] Cannot spawn enemy - spawner not in scene tree!")
		return

	if enemy_scenes.is_empty():
		return

	# Pick a random enemy scene from the pool
	var enemy_scene = enemy_scenes[randi() % enemy_scenes.size()]

	# Calculate spawn position in a circle
	var angle = (TAU / total) * index  # Evenly distribute around circle
	var offset = Vector3(
		cos(angle) * spawn_radius,
		spawn_height,
		sin(angle) * spawn_radius
	)
	var spawn_pos = global_position + offset

	# Generate unique name for multiplayer sync
	_enemy_id_counter += 1
	var enemy_name = "Enemy_" + str(current_wave) + "_" + str(_enemy_id_counter)

	# Spawn on all clients via RPC (call_local will spawn on server too)
	var enemy_scene_path = enemy_scene.resource_path
	rpc("_spawn_enemy_on_client", enemy_name, spawn_pos, enemy_scene_path)

## RPC to spawn enemy on all clients (including server via call_local)
@rpc("any_peer", "call_local", "reliable")
func _spawn_enemy_on_client(enemy_name: String, spawn_pos: Vector3, scene_path: String):
	# Load the enemy scene
	var enemy_scene = load(scene_path)
	if not enemy_scene:
		push_error("[EnemySpawner] Failed to load enemy scene: ", scene_path)
		return

	# Instantiate enemy
	var enemy = enemy_scene.instantiate()
	enemy.name = enemy_name
	enemy.position = spawn_pos

	# Find enemies container
	var level = get_tree().get_current_scene()
	var enemies_container = null
	if level and level.has_node("EnemiesContainer"):
		enemies_container = level.get_node("EnemiesContainer")
	else:
		push_error("[EnemySpawner] EnemiesContainer not found!")
		return

	# Add to scene
	enemies_container.add_child(enemy, true)

	# Only server tracks active enemies and connects signals
	if multiplayer.is_server():
		active_enemies.append(enemy)

		# Connect death signal if enemy is BaseEnemy
		if enemy is BaseEnemy:
			enemy.died.connect(_on_enemy_died.bind(enemy))

		enemy_spawned.emit(enemy)

	print("[EnemySpawner] Spawned ", enemy.name, " at ", enemy.global_position, " on peer ", multiplayer.get_unique_id())

## Called when an enemy dies
func _on_enemy_died(killer_id: int, enemy: Node):
	if not multiplayer.is_server():
		return

	print("[EnemySpawner] Enemy ", enemy.name, " defeated by ", killer_id)

	# Credit kill gold to the killing player (server decides, credits their peer)
	if killer_id > 0 and Network.players.has(killer_id) and enemy is BaseEnemy:
		GameState.server_credit_kill(killer_id, enemy.gold_reward)

	# Will be cleaned up in _update_active_enemies

## Update list of active enemies and check if wave complete
func _update_active_enemies():
	if not multiplayer.is_server():
		return

	# Remove dead/invalid enemies from active list
	var alive_count = 0
	for enemy in active_enemies:
		if is_instance_valid(enemy) and enemy is BaseEnemy and not enemy.is_dead:
			alive_count += 1

	# Check if wave is complete
	if active_enemies.size() > 0 and alive_count == 0:
		_on_wave_completed()

## Called when all enemies in wave are defeated
func _on_wave_completed():
	if not multiplayer.is_server():
		return

	print("[EnemySpawner] Wave ", current_wave, " completed!")
	wave_completed.emit(current_wave)

	# Wave-clear bonus for every living player (scales with wave number)
	var wave_bonus: int = 25 + current_wave * 5
	for peer_id in Network.players.keys():
		GameState.server_credit_gold(peer_id, wave_bonus)

	# Clean up dead enemies after a delay
	await get_tree().create_timer(2.0).timeout
	_cleanup_dead_enemies()

	all_enemies_defeated.emit()

	# Auto-start next wave if enabled
	if auto_start_next_wave:
		_waiting_for_next_wave = true
		_wave_delay_timer = wave_delay
		print("[EnemySpawner] Next wave starts in ", wave_delay, " seconds")

## Remove dead enemies from the scene
func _cleanup_dead_enemies():
	var cleaned = 0
	for enemy in active_enemies:
		if is_instance_valid(enemy) and enemy is BaseEnemy and enemy.is_dead:
			enemy.queue_free()
			cleaned += 1

	active_enemies.clear()
	print("[EnemySpawner] Cleaned up ", cleaned, " defeated enemies")

## Manual wave control
func start_next_wave():
	if not multiplayer.is_server():
		return
	start_wave()

func stop_waves():
	_waiting_for_next_wave = false

## Get current wave info
func get_alive_enemy_count() -> int:
	var count = 0
	for enemy in active_enemies:
		if is_instance_valid(enemy) and enemy is BaseEnemy and not enemy.is_dead:
			count += 1
	return count

func is_wave_active() -> bool:
	return get_alive_enemy_count() > 0

## Create debug visualization circle
func _create_debug_circle():
	# Create a circle mesh to show spawn radius
	_debug_circle = MeshInstance3D.new()
	_debug_circle.name = "DebugSpawnCircle"

	# Create circle mesh using ImmediateMesh
	var immediate_mesh = ImmediateMesh.new()
	var material = StandardMaterial3D.new()
	material.albedo_color = Color(1, 0.5, 0, 0.6)  # Orange
	material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
	material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
	material.cull_mode = BaseMaterial3D.CULL_DISABLED

	# Draw circle
	immediate_mesh.surface_begin(Mesh.PRIMITIVE_LINE_STRIP)
	var segments = 64
	for i in range(segments + 1):
		var angle = (TAU / segments) * i
		var x = cos(angle) * spawn_radius
		var z = sin(angle) * spawn_radius
		immediate_mesh.surface_add_vertex(Vector3(x, spawn_height, z))
	immediate_mesh.surface_end()

	_debug_circle.mesh = immediate_mesh
	_debug_circle.material_override = material
	_debug_circle.visible = show_spawn_radius
	add_child(_debug_circle)

## Update debug visualization (useful when changing spawn_radius in editor)
func _process(_delta):
	# Update circle visibility
	if _debug_circle:
		_debug_circle.visible = show_spawn_radius

	# Server spawning logic (check peer is assigned first)
	if multiplayer.multiplayer_peer == null or not multiplayer.is_server():
		return

	# Timed waves - spawn a fresh wave on a repeating interval
	if _auto_waves_active:
		_auto_wave_timer -= _delta
		if _auto_wave_timer <= 0:
			_auto_wave_timer = wave_interval
			start_wave()

	# Handle wave delay timer
	if _waiting_for_next_wave:
		_wave_delay_timer -= _delta
		if _wave_delay_timer <= 0:
			_waiting_for_next_wave = false
			start_wave()

	# Check if all enemies defeated
	_update_active_enemies()
