class_name VoicelineComponent
extends Node

@export_node_path("AudioStreamPlayer", "AudioStreamPlayer2D", "AudioListener3D")
var audio_players: Array[NodePath] = []:
	set = set_audio_players
@export var voiceline_chains: Dictionary[StringName, VoicelineChain] = {}
@export var cache_voicelines: bool = false ## TODO: preload all voicelines when they need the be loaded.

var voiceline_players: Array[Node] = []
var next_voicelines: Array[VoicelineChain] = []
var current_voiceline_chain_index: int = 0
var _reference_player: Node


func set_audio_players(players: Array[NodePath]) -> void:
	audio_players = players
	_update_player_cache()


func push_voiceline(voiceline_chain: VoicelineChain) -> void:
	next_voicelines.append(voiceline_chain)


func push_next_voiceline() -> void:
	var voiceline: VoicelineChain = next_voicelines.front()

	if is_instance_valid(voiceline) and current_voiceline_chain_index < voiceline.voicelines.size():
		current_voiceline_chain_index += 1
		_play_voiceline(voiceline.voicelines[current_voiceline_chain_index])
		return

	next_voicelines.remove_at(0)
	voiceline = next_voicelines.front()
	current_voiceline_chain_index = 0

	if is_instance_valid(voiceline):
		_play_voiceline(voiceline.voicelines.front())


func play_voiceline(vo_name: StringName) -> void:
	if voiceline_chains.has(vo_name):
		push_voiceline(voiceline_chains[vo_name])
	else:
		push_warning("[%s] No voiceline with the name '%s' found." % [self, vo_name])


func is_audio_player(player: Node) -> bool:
	return (
		is_instance_valid(player)
		and (
			player is AudioStreamPlayer
			or player is AudioStreamPlayer2D
			or player is AudioStreamPlayer3D
		)
	)


func _play_voiceline(voiceline_data: VoicelineData) -> void:
	var voice: AudioStream = load(voiceline_data.voiceline_path)

	for player: Node in voiceline_players:
		player.play(voice)


func _on_voiceline_finished() -> void:
	push_next_voiceline()


func _update_player_cache() -> void:
	voiceline_players.clear()

	for audio_player: NodePath in audio_players:
		var player: Node = get_node_or_null(audio_player)

		if is_audio_player(player):
			voiceline_players.append(player)
			_reference_player = player

	_reference_player.finished.connect(_on_voiceline_finished)
