@tool
extends VBoxContainer


signal file_selected(file_path: String)
signal file_popup_menu_requested(at_position: Vector2)
signal file_double_clicked(file_path: String)
signal file_middle_clicked(file_path: String)


const DialogueConstants = preload("../constants.gd")

const MODIFIED_SUFFIX = "(*)"


@export var icon: Texture2D

@onready var filter_edit: LineEdit = $FilterEdit
@onready var list: ItemList = $List

var file_map: Dictionary = {}

var current_file_path: String = ""
var last_selected_file_path: String = ""

var files: PackedStringArray = []:
	set(next_files):
		files = next_files
		files.sort()
		update_file_map()
		apply_filter()
	get:
		return files

var unsaved_files: Array[String] = []

var filter: String = "":
	set(next_filter):
		filter = next_filter
		apply_filter()
	get:
		return filter


func _ready() -> void:
	apply_theme()

	filter_edit.placeholder_text = DialogueConstants.translate(&"files_list.filter")


func focus_filter() -> void:
	filter_edit.grab_focus()


func select_file(file: String) -> void:
	list.deselect_all()
	for i in range(0, list.get_item_count()):
		var item_text = list.get_item_text(i).replace(MODIFIED_SUFFIX, "")
		if item_text == get_nice_file(file, item_text.count("/") + 1):
			list.select(i)
			last_selected_file_path = file


func mark_file_as_unsaved(file: String, is_unsaved: bool) -> void:
	if not file in unsaved_files and is_unsaved:
		unsaved_files.append(file)
	elif file in unsaved_files and not is_unsaved:
		unsaved_files.erase(file)
	apply_filter()


func update_file_map() -> void:
	file_map = {}
	for file in files:
		var nice_file: String = get_nice_file(file)

		# See if a value with just the file name is already in the map
		for key in file_map.keys():
			if file_map[key] == nice_file:
				var bit_count = nice_file.count("/") + 2

				var existing_nice_file = get_nice_file(key, bit_count)
				nice_file = get_nice_file(file, bit_count)

				while nice_file == existing_nice_file:
					bit_count += 1
					existing_nice_file = get_nice_file(key, bit_count)
					nice_file = get_nice_file(file, bit_count)

				file_map[key] = existing_nice_file

		file_map[file] = nice_file


func get_nice_file(file_path: String, path_bit_count: int = 1) -> String:
	var bits = file_path.replace("res://", "").replace(".dialogue", "").split("/")
	bits = bits.slice(-path_bit_count)
	return "/".join(bits)


func apply_filter() -> void:
	list.clear()
	for file in file_map.keys():
		if filter == "" or filter.to_lower() in file.to_lower():
			var nice_file = file_map[file]
			if file in unsaved_files:
				nice_file += MODIFIED_SUFFIX
			var new_id := list.add_item(nice_file)
			list.set_item_icon(new_id, icon)

	select_file(current_file_path)


func apply_theme() -> void:
	if is_instance_valid(filter_edit):
		filter_edit.right_icon = get_theme_icon("Search", "EditorIcons")
	if is_instance_valid(list):
		list.add_theme_stylebox_override("panel", get_theme_stylebox("panel", "Panel"))


### Signals


func _on_theme_changed() -> void:
	apply_theme()


func _on_filter_edit_text_changed(new_text: String) -> void:
	self.filter = new_text


func _on_list_item_clicked(index: int, at_position: Vector2, mouse_button_index: int) -> void:
	var item_text = list.get_item_text(index).replace(MODIFIED_SUFFIX, "")
	var file = file_map.find_key(item_text)

	if mouse_button_index == MOUSE_BUTTON_LEFT or mouse_button_index == MOUSE_BUTTON_RIGHT:
		select_file(file)
		file_selected.emit(file)
		if mouse_button_index == MOUSE_BUTTON_RIGHT:
			file_popup_menu_requested.emit(at_position)

	if mouse_button_index == MOUSE_BUTTON_MIDDLE:
		file_middle_clicked.emit(file)


func _on_list_item_activated(index: int) -> void:
	var item_text = list.get_item_text(index).replace(MODIFIED_SUFFIX, "")
	var file = file_map.find_key(item_text)
	select_file(file)
	file_double_clicked.emit(file)
