class_name RainAmbience
extends AudioStreamPlayer

const RAIN_STREAM_PATH: String = (
	"res://audio/ambience/rain_loop_ontario.ogg"
)
const SILENT_VOLUME_DB: float = -60.0

@export_range(-40.0, 0.0, 0.5) var rain_volume_db: float = -8.0
@export_range(0.0, 10.0, 0.1) var fade_seconds: float = 2.5

var _weather_service: WorldWeatherService
var _fade_tween: Tween
var _is_active: bool = false


func _ready() -> void:
	bus = &"Environment"
	var rain_stream := load(RAIN_STREAM_PATH) as AudioStreamOggVorbis
	var runtime_stream := (
		rain_stream.duplicate() as AudioStreamOggVorbis
		if rain_stream != null
		else null
	)
	if runtime_stream != null:
		runtime_stream.loop = true
		stream = runtime_stream
	volume_db = SILENT_VOLUME_DB


func configure(weather_service: WorldWeatherService) -> void:
	if (
		_weather_service != null
		and _weather_service.weather_changed.is_connected(
			_on_weather_changed
		)
	):
		_weather_service.weather_changed.disconnect(_on_weather_changed)
	_weather_service = weather_service
	if (
		_weather_service != null
		and not _weather_service.weather_changed.is_connected(
			_on_weather_changed
		)
	):
		_weather_service.weather_changed.connect(_on_weather_changed)


func set_active(active: bool) -> void:
	if _is_active == active:
		return
	_is_active = active
	if not active:
		_silence_immediately()
		return
	_transition_to_rain(
		_weather_service != null and _weather_service.is_raining()
	)


func _on_weather_changed(
	weather: WorldWeatherService.Weather,
	_seconds_remaining: float,
) -> void:
	_transition_to_rain(weather == WorldWeatherService.Weather.RAINY)


func _transition_to_rain(is_raining: bool) -> void:
	if not _is_active:
		return
	_stop_fade()
	if is_raining:
		if stream == null:
			return
		if not playing:
			volume_db = SILENT_VOLUME_DB
			play()
		_fade_volume_to(rain_volume_db, false)
		return
	if playing:
		_fade_volume_to(SILENT_VOLUME_DB, true)


func _fade_volume_to(target_volume_db: float, stop_after_fade: bool) -> void:
	if fade_seconds <= 0.0:
		volume_db = target_volume_db
		if stop_after_fade:
			_finish_fade_out()
		return
	_fade_tween = create_tween()
	_fade_tween.set_trans(Tween.TRANS_SINE)
	_fade_tween.set_ease(Tween.EASE_IN_OUT)
	_fade_tween.tween_property(
		self,
		"volume_db",
		target_volume_db,
		fade_seconds,
	)
	if stop_after_fade:
		_fade_tween.tween_callback(_finish_fade_out)


func _finish_fade_out() -> void:
	if _weather_service != null and _weather_service.is_raining():
		return
	stop()
	volume_db = SILENT_VOLUME_DB
	_fade_tween = null


func _silence_immediately() -> void:
	_stop_fade()
	stop()
	volume_db = SILENT_VOLUME_DB


func _stop_fade() -> void:
	if _fade_tween == null:
		return
	_fade_tween.kill()
	_fade_tween = null
