class_name VolumeSlider extends VBoxContainer
## Input element for adjusting the volume of a single bus.

const SCENE := preload("res://src/ui/menus/settings_menu/volume_slider/volume_slider.tscn")
const VOLUME_FACTOR := 50.0

@export var bus_idx: int

var value: float:
	get:
		return slider.value
	set(v):
		slider.set_value_no_signal(v)
		spin_box.set_value_no_signal(v)
		_set_bus_volume(v)

var _applied_value: float

@onready var bus_name: Label = %BusName
@onready var slider: VSlider = %Slider
@onready var spin_box: SpinBox = %SpinBox
@onready var audio_demo: AudioStreamPlayer = %AudioDemo


func _ready() -> void:
	bus_name.text = AudioServer.get_bus_name(bus_idx)
	audio_demo.bus = bus_name.text
	_applied_value = _db_to_volume(AudioServer.get_bus_volume_db(bus_idx))
	value = _applied_value


func _exit_tree() -> void:
	# Revert volume to the value from the last time `apply` was called
	_set_bus_volume(_applied_value)


func _db_to_volume(db: float) -> float:
	return db_to_linear(db) * VOLUME_FACTOR


func _volume_to_db(volume: float) -> float:
	return linear_to_db(volume / VOLUME_FACTOR)


func _on_component_value_changed(new_value: float) -> void:
	value = new_value


func _set_bus_volume(new_value: float) -> void:
	AudioServer.set_bus_volume_db(bus_idx, _volume_to_db(new_value))


func apply() -> void:
	# Prevent value from being reverted during destructor.
	_applied_value = value


func _on_slider_drag_ended(value_changed: bool) -> void:
	if value_changed:
		audio_demo.play()


func _on_spin_box_value_changed(_new_value: float) -> void:
	audio_demo.play()


static func create(_bus_idx: int) -> VolumeSlider:
	var instance: VolumeSlider = SCENE.instantiate()
	instance.bus_idx = _bus_idx
	return instance
