class_name World
extends Node3D


@export_group("Nodes and Scenes")
@export var blocks_container: Node3D ## Container where spawned blocks are added
@export var dropped_items_container: Node3D ## Container where spawned dropped items are added
@export var player_scene: PackedScene
@export var spawn_position: Marker3D


func _ready() -> void:
	Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	EntityManager.create_block.connect(_create_block)
	EntityManager.drop_block.connect(_create_dropped_block)
	EntityManager.reset_world.connect(clear_world)
	EntityManager.spawn_player.connect(spawn_player)
	SaveGameManager.load_complete.connect(_on_load_save_complete)
	SignalManager.open_pause_menu.connect(_on_open_pause_menu)
	SignalManager.resume_game.connect(_on_resume_game)

	clear_world()
	create_world()
	SaveGameManager.start_autosave.emit()

## For resetting/emptying the world to allow for load_game or generating a new world
func clear_world() -> void:
	for block: Block in blocks_container.get_children():
		block.queue_free()

	for block: DroppedBlock in dropped_items_container.get_children():
		block.queue_free()

func create_world() -> void:
	generate_world()
	_create_test_blocks()

	var default_transform: Transform3D = Transform3D()
	default_transform.origin = spawn_position.position
	spawn_player(default_transform)

func generate_world() -> void:
	for x: int in range(-10, 11):
		for z: int in range(-10, 11):
			var ground_position: Vector3 = Vector3(x, 0, z)

			var random: int = randi_range(0, 1)
			if random:
				# Just for testing.. Would make more sense to just call _create_block() directly
				EntityManager.create_block.emit("001", ground_position)
			else:
				EntityManager.create_block.emit("002", ground_position)

func spawn_player(player_position: Transform3D) -> void:
	var players: Array = get_tree().get_nodes_in_group("Player")
	for player: Player in players:
		player.queue_free()
		await player.tree_exited

	var player: Player = player_scene.instantiate()
	player.transform = player_position
	player.name = "Player"
	add_child(player)


func _create_block(id: String, block_position: Vector3) -> void:
	var block: Block = Globals.BLOCK_PREFAB.instantiate()
	block.position = block_position
	block.set_id(id)

	blocks_container.add_child(block)

func _create_dropped_block(id: String, start_position: Vector3, direction: Vector3 = Vector3.ZERO, velocity: float = 0.0) -> void:
	var block: DroppedBlock = Globals.DROPPED_BLOCK_PREFAB.instantiate()
	dropped_items_container.add_child(block)
	block.initialize(id, start_position, direction, velocity)

func _create_test_blocks() -> void:
	var test_blocks: Array = ["001", "002", "003", "004", "005", "006"]
	for index: int in range(1, test_blocks.size() + 1):
		_create_block("00" + str(index), Vector3(index, 1, -3))
		_create_block("00" + str(index), Vector3(index, 2, -4))
		_create_block("00" + str(index), Vector3(index, 3, -5))
		_create_dropped_block("00" + str(index), Vector3(index, 2, -3))


func _on_reset_world() -> void:
	clear_world()

func _on_load_save_complete() -> void:
	clear_world()
	SaveGameManager.apply_save.emit()
	SaveGameManager.start_autosave.emit()

func _on_open_pause_menu() -> void:
	SaveGameManager.stop_autosave.emit()

func _on_resume_game() -> void:
	SaveGameManager.start_autosave.emit()