class_name TileGround
extends Node3D
@export var ground_tile: PackedScene
@export var map_width: int = Global.map_width
@export var map_height: int = Global.map_height
@export var tile_size: float = 2.0
@export var chunk_size: int = 2
@export var view_distance: int = 2
@export var tiles_per_frame: int = 3 # How many tiles to create per frame
var loaded_chunks: Dictionary = {}
var player_position: Vector3
var last_chunk_pos: Vector2i = Vector2i(-999, -999)
var loading_chunks: Dictionary = {} # Track chunks currently being loaded

func _ready() -> void:
	create_tiles_chunked()

func create_tiles_chunked() -> void:
	var player = %Player
	if player:
		player_position = player.global_position
		update_chunks(player_position)
	else:
		Log.pr("Player not found, loading chunks around origin")
		update_chunks(Vector3.ZERO)

func update_chunks(player_pos: Vector3) -> void:
	player_position = player_pos
	
	var current_chunk = Vector2i(
		int(player_pos.x / (chunk_size * tile_size)),
		int(player_pos.z / (chunk_size * tile_size))
	)
	
	if current_chunk == last_chunk_pos:
		return
	
	last_chunk_pos = current_chunk
	Log.pr("CHUNK CHANGE - New chunk: ", current_chunk)
	
	# Determine which chunks should be loaded
	var chunks_to_load: Array[Vector2i] = []
	for x in range(-view_distance, view_distance + 1):
		for z in range(-view_distance, view_distance + 1):
			chunks_to_load.append(current_chunk + Vector2i(x, z))
	
	# LOADING new chunks
	for chunk_pos in chunks_to_load:
		if chunk_pos not in loaded_chunks and chunk_pos not in loading_chunks:
			loading_chunks[chunk_pos] = true
			load_chunk_async(chunk_pos)
	
	# UNLOADING far chunks
	var chunks_to_unload: Array[Vector2i] = []
	for chunk_pos in loaded_chunks.keys():
		if chunk_pos not in chunks_to_load:
			chunks_to_unload.append(chunk_pos)
	
	for chunk_pos in chunks_to_unload:
		unload_chunk(chunk_pos)

func load_chunk_async(chunk_pos: Vector2i) -> void:
	if not ground_tile:
			Log.pr("ground_tile is null!")
			loading_chunks.erase(chunk_pos)
			return

	var chunk_node = Node3D.new()
	chunk_node.name = "Chunk_%d_%d" % [chunk_pos.x, chunk_pos.y]
	add_child(chunk_node)
	
	var start_x = chunk_pos.x * chunk_size * tile_size - (chunk_size * tile_size) / 2.0
	var start_z = chunk_pos.y * chunk_size * tile_size - (chunk_size * tile_size) / 2.0
	
	#var tiles_created = 0
	var tiles_this_frame = 0
	
	for x in range(chunk_size):
		for z in range(chunk_size):
			var tile_instance = ground_tile.instantiate()
			tile_instance.set_grid_location((chunk_pos.x * chunk_size) + x, (chunk_pos.y * chunk_size) + z)
			tile_instance.position = Vector3(
				start_x + (x * tile_size),
				0,
				start_z + (z * tile_size)
			)
			chunk_node.add_child(tile_instance)
			
			#tiles_created += 1
			tiles_this_frame += 1
			
			# Yield after creating a certain number of tiles
			if tiles_this_frame >= tiles_per_frame:
				tiles_this_frame = 0
				await get_tree().process_frame

	loaded_chunks[chunk_pos] = chunk_node
	loading_chunks.erase(chunk_pos)


func unload_chunk(chunk_pos: Vector2i) -> void:
	if chunk_pos in loaded_chunks:
			var chunk_node = loaded_chunks[chunk_pos]
			chunk_node.queue_free()
			loaded_chunks.erase(chunk_pos)
