extends Node3D
class_name Train

signal speed_changed(new_speed: float)

@export_group("Train")
@export var base_speed: float = 15.0
@export var max_speed: float = 50.0
@export var min_speed: float = 3.0
@export var acceleration: float = 12.0
@export var wagon_spacing: float = 5.5

var num_wagons: int
var group_name: String  = ""

var locomotive_model_resources: Array[String] = [
	"train-diesel-a.obj",
	"train-diesel-b.obj",
	"train-diesel-box-a.obj",
	"train-diesel-c.obj"
	]
	
var wagon_model_resources: Array[String] = [
	"train-carriage-container-blue.obj",
	"train-carriage-flatbed-wood.obj",
	"train-carriage-lumber.obj",
	"train-carriage-tank-large.obj",
	"train-diesel-box-b.obj",
	"train-diesel-box-c.obj"
	]

# Riferimento al generatore (settato da main.gd)
var track_generator: TrackGenerator

# Stato
var current_speed: float = 15.0
var distance_traveled: float = 0.0
var locomotive: Node3D
var wagons: Array = []
var wagon_distances: Array = []


func _ready() -> void:
	# Aspetta un frame per assicurarsi che track_generator sia settato
	await get_tree().process_frame
	await get_tree().process_frame
	_create_train()
	current_speed = base_speed


func _remove_train():
	for node in get_tree().get_nodes_in_group(group_name):
		node.queue_free()


func _create_train() -> void:
	_remove_train()
	_create_locomotive()
	wagons = []
	wagon_distances = []
	num_wagons = randi_range(1, 10)
	_create_wagons()


func _create_locomotive() -> void:
	var locomotive_model = locomotive_model_resources.pick_random()
	locomotive = load_model("res://resources/train kit/" + locomotive_model, "Locomotive")
	locomotive.transform.rotated(Vector3(1, 0, 0), 180.0)
	group_name = "locomotive" + str(Time.get_unix_time_from_system())
	locomotive.add_to_group(group_name)
	
	add_child(locomotive)


func _create_wagons() -> void:
	var loco_length = 0
	for child in locomotive.get_children():
		if child is MeshInstance3D:
			var aabb = child.get_aabb()
			loco_length = aabb.size.z
	
	for i in range(num_wagons):	
		var wagon_model = wagon_model_resources.pick_random()
		var wagon = load_model("res://resources/train kit/" + wagon_model, "Wagon_%d" % i)
		wagon.transform.rotated(Vector3(1, 0, 0), 180.0)
		wagon.add_to_group(group_name)
		add_child(wagon)
		
		wagons.append(wagon)
		wagon_distances.append(loco_length if num_wagons == 1 else 0 * 0.5 + (i + 1) * wagon_spacing)
		_position_wagons_initial()


func _position_wagons_initial() -> void:
	# Posiziona i vagoni sul tracciato all'avvio
	if not track_generator:
		return
	
	for i in range(wagons.size()):
		var wagon_dist = distance_traveled - wagon_distances[i]
		# All'inizio i vagoni potrebbero essere "prima" della partenza
		# quindi li posizioniamo dove possibile
		if wagon_dist < 0:
			wagon_dist = 0
		
		var wagon_data = track_generator.get_position_on_track(wagon_dist)
		if wagon_data["valid"]:
			_apply_transform(wagons[i], wagon_data["position"], wagon_data["direction"])


func load_model(path: String, node_name: String) -> Node3D:
	var mesh = OBJLoader.load_obj(path)
	if mesh == null:
		return null

	# Crea un nodo contenitore
	var newobj = Node3D.new()
	newobj.name = node_name

	# Crea il mesh instance come figlio
	var mesh_instance = MeshInstance3D.new()
	mesh_instance.mesh = mesh
	newobj.add_child(mesh_instance)

	return newobj
	
	
func _process(delta: float) -> void:
	if not track_generator or not locomotive:
		return
	
	_handle_input(delta)
	_update_movement(delta)
	_update_track()


func _handle_input(delta: float) -> void:
	if Input.is_action_pressed("speed_up"):
		current_speed = min(current_speed + acceleration * delta, max_speed)
		speed_changed.emit(current_speed)
	elif Input.is_action_pressed("speed_down"):
		current_speed = max(current_speed - acceleration * delta, min_speed)
		speed_changed.emit(current_speed)
	elif Input.is_action_pressed("change_train"):
		_create_train()
		current_speed = base_speed

func _update_movement(delta: float) -> void:
	distance_traveled += current_speed * delta
	
	# Locomotiva
	var loco_data = track_generator.get_position_on_track(distance_traveled)
	if loco_data["valid"]:
		_apply_transform(locomotive, loco_data["position"], loco_data["direction"])
	
	# Vagoni
	for i in range(wagons.size()):
		var wagon_dist = distance_traveled - wagon_distances[i]
		if wagon_dist < 0:
			wagon_dist = 0
		
		var wagon_data = track_generator.get_position_on_track(wagon_dist)
		if wagon_data["valid"]:
			_apply_transform(wagons[i], wagon_data["position"], wagon_data["direction"])


func _apply_transform(node: Node3D, pos: Vector3, direction: Vector3) -> void:
	node.global_position = pos
	
	if direction.length_squared() > 0.001:
		var target = pos - direction
		var up = Vector3.UP
		if abs(direction.dot(up)) > 0.99:
			up = Vector3.RIGHT
		node.look_at(target, up)


func _update_track() -> void:
	track_generator.update_track(distance_traveled)


func get_locomotive_position() -> Vector3:
	if locomotive:
		return locomotive.global_position
	return Vector3.ZERO


func get_speed() -> float:
	return current_speed
