extends State


# Reference to the currently playing dialog manager
var _dialog_manager: ESCDialogManager = null

# Character that is talking
var _character: String

# UI to use for the dialog
var _type: String

# Translation key
var _key: String = ""

# Text to say
var _text: String

var _ready_to_say: bool

# flag for whether the dialog manager has started to "say" to ensure that it has
# prior to exiting this state as other states need this to happen to continue
# (other states rely on the setup that the dialog manager does)
var _say_started: bool

var _stop_talking_animation_on_option: String


func initialize(dialog_manager: ESCDialogManager, character: String, text: String, type: String, key: String) -> void:
	_dialog_manager = dialog_manager
	_character = character
	_text = text
	_type = type
	_key = key
	_stop_talking_animation_on_option = \
		ESCProjectSettingsManager.get_setting(SimpleDialogSettings.STOP_TALKING_ANIMATION_ON)


func handle_input(_event):
	if _event is InputEventMouseButton and _event.pressed:
		if escoria.inputs_manager.input_mode != \
			escoria.inputs_manager.INPUT_NONE and \
			_dialog_manager != null:

			var left_click_action = ESCProjectSettingsManager.get_setting(SimpleDialogSettings.LEFT_CLICK_ACTION)

			_handle_left_click_action(left_click_action)


func _handle_left_click_action(left_click_action: String) -> void:
	match left_click_action:
		SimpleDialogSettings.LEFT_CLICK_ACTION_SPEED_UP:
			if _dialog_manager.say_visible.is_connected(_on_say_visible):
				_dialog_manager.say_visible.disconnect(_on_say_visible)

			escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_fast'")
			finished.emit("say_fast")
		SimpleDialogSettings.LEFT_CLICK_ACTION_INSTANT_FINISH:
			if _dialog_manager.say_visible.is_connected(_on_say_visible):
				_dialog_manager.say_visible.disconnect(_on_say_visible)

			escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'say_finish'")
			finished.emit("say_finish")

	get_viewport().set_input_as_handled()


func enter():
	escoria.logger.trace(self, "Dialog State Machine: Entered 'say'.")

	_say_started = false

	if not _dialog_manager.say_visible.is_connected(_on_say_visible):
		_dialog_manager.say_visible.connect(_on_say_visible)

	if _key and not _key.is_empty():
		var _speech_resource = _get_voice_file(_key)

		if _speech_resource == "":
			escoria.logger.warn(
				self,
				"Unable to find voice file with key '%s'." % _key
			)
		else:
			(
				escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
				 as ESCSpeechPlayer
			).set_state(_speech_resource)

			if _stop_talking_animation_on_option == SimpleDialogSettings.STOP_TALKING_ANIMATION_ON_END_OF_AUDIO:
				if not (
					escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
					 as ESCSpeechPlayer
				).stream.finished.is_connected(_on_audio_finished):

					(
						escoria.object_manager.get_object(escoria.object_manager.SPEECH).node\
						 as ESCSpeechPlayer
					).stream.finished.connect(_on_audio_finished)

		var translated_text: String = tr(_key)

		# Only update the text if the translated text was found; otherwise, raise
		# a warning and use the original, untranslated text.
		if translated_text == _key:
			escoria.logger.warn(
				self,
				"Unable to find translation key '%s'. Using untranslated text." % _key
			)
		else:
			_text = translated_text

	_ready_to_say = true


func exit() -> void:
	if not _say_started:
		_dialog_manager.do_say(_character, _text)
		_say_started = true


func update(_delta):
	if _ready_to_say:
		_dialog_manager.do_say(_character, _text)
		_say_started = true
		_ready_to_say = false


# Find the matching voice output file for the given key
#
# #### Parameters
#
# - key: Text key provided
# - start: Starting folder to search for voices
#
# **Returns** The path to the matching voice file
func _get_voice_file(key: String, start: String = "") -> String:
	if start == "":
		start = ESCProjectSettingsManager.get_setting(
			ESCProjectSettingsManager.SPEECH_FOLDER
		)
	var _dir = DirAccess.open(start)
	if _dir != null:
		_dir.list_dir_begin() # TODOConverter3To4 fill missing arguments https://github.com/godotengine/godot/pull/40547
		var file_name = _dir.get_next()
		while file_name != "":
			if _dir.current_is_dir():
				var _voice_file = _get_voice_file(
					key,
					start.path_join(file_name)
				)
				if _voice_file != "":
					return _voice_file
			else:
				if file_name == "%s.%s.import" % [
					key,
					ESCProjectSettingsManager.get_setting(
						ESCProjectSettingsManager.SPEECH_EXTENSION
					)
				]:
					return start.path_join(file_name.trim_suffix(".import"))
			file_name = _dir.get_next()
	return ""


func _on_say_visible() -> void:
	escoria.logger.trace(self, "Dialog State Machine: 'say' -> 'visible'")
	finished.emit("visible")


func _on_audio_finished() -> void:
	_dialog_manager.voice_audio_finished()
