extends Node

const MASTER: StringName = &"Master"
const MUSIC: StringName = &"Music"
const SFX: StringName = &"SFX"
const AMBIENCE: StringName = &"Ambient"


func play_audio(stream: AudioStream, bus: StringName, force_restart: bool = false) -> void:
	if is_playing_audio(stream, bus):
		if force_restart:
			var existing_player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus)
			existing_player.stop()
			existing_player.play()

		return

	var player: AudioStreamPlayer = create_audio_player(stream, bus)
	player.finished.connect(stop_audio.bind(stream, bus))

	add_child(player)
	player.play()


func stop_audio(stream: AudioStream, bus: StringName) -> void:
	var player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus)

	if is_instance_valid(player):
		player.queue_free()


func fade_audio(
	stream: AudioStream,
	volume_db: float,
	duration: float,
	bus: StringName,
	stop_on_finish: bool = false
) -> void:
	var player: AudioStreamPlayer = get_audio_player_for_stream(stream, bus)

	if not is_instance_valid(player):
		return

	var tween: Tween = create_tween().bind_node(player)
	tween.tween_property(player, ^"volume_db", volume_db, duration)

	if stop_on_finish:
		tween.tween_callback(stop_audio.bind(stream, bus))

	await tween.finished


func fade_audio_linear(
	stream: AudioStream,
	volume_linear: float,
	bus: StringName,
	duration: float,
	stop_on_finish: bool = false
) -> void:
	await fade_audio(stream, linear_to_db(volume_linear), duration, bus, stop_on_finish)


func get_audio_player_for_stream(stream: AudioStream, bus: StringName) -> AudioStreamPlayer:
	for player: AudioStreamPlayer in get_children():
		if player.stream == stream and player.bus == bus:
			return player

	return null


func is_playing_audio(stream: AudioStream, bus: StringName) -> bool:
	return is_instance_valid(get_audio_player_for_stream(stream, bus))


func flush_audio_by_bus(bus: StringName) -> void:
	for player: AudioStreamPlayer in get_children():
		if player.bus == bus:
			player.queue_free()


func create_audio_player(stream: AudioStream, bus: StringName) -> AudioStreamPlayer:
	var player := AudioStreamPlayer.new()
	player.bus = bus
	player.stream = stream
	return player
