@tool
extends "res://addons/godot_mcp/commands/base_command.gd"


func get_commands() -> Dictionary:
	return {
		"get_input_actions": _get_input_actions,
		"set_input_action": _set_input_action,
	}


func _get_input_actions(params: Dictionary) -> Dictionary:
	var filter: String = optional_string(params, "filter", "")
	var include_builtin: bool = optional_bool(params, "include_builtin", false)

	var actions: Dictionary = {}
	for action: StringName in InputMap.get_actions():
		var action_str := str(action)
		if not include_builtin:
			# Skip built-in UI actions
			if action_str.begins_with("ui_"):
				continue
			# Skip editor-registered actions (spatial_editor/*, etc.) — the addon
			# runs in the editor process, so InputMap also carries the editor's
			# own actions, which are not part of the project's InputMap
			if not ProjectSettings.has_setting("input/" + action_str):
				continue
		# Apply filter
		if not filter.is_empty() and not action_str.contains(filter):
			continue

		var events: Array = []
		for event: InputEvent in InputMap.action_get_events(action):
			events.append(_serialize_event(event))

		actions[action_str] = {
			"deadzone": InputMap.action_get_deadzone(action),
			"events": events,
		}

	return success({"actions": actions, "count": actions.size()})


func _set_input_action(params: Dictionary) -> Dictionary:
	var result := require_string(params, "action")
	if result[1] != null:
		return result[1]
	var action_name: String = result[0]

	if not params.has("events") or not params["events"] is Array:
		return error_invalid_params("'events' array is required")
	var event_defs: Array = params["events"]

	var deadzone: float = float(params.get("deadzone", 0.5))

	# Build the events array
	var events: Array[InputEvent] = []
	for event_def in event_defs:
		if not event_def is Dictionary:
			continue
		var event := _parse_event(event_def)
		if event != null:
			events.append(event)

	# Save to ProjectSettings
	var setting_value := {
		"deadzone": deadzone,
		"events": events,
	}

	ProjectSettings.set_setting("input/" + action_name, setting_value)
	var err := ProjectSettings.save()
	if err != OK:
		return error_internal("Failed to save project settings: %s" % error_string(err))

	# Also update the runtime InputMap
	if not InputMap.has_action(action_name):
		InputMap.add_action(action_name, deadzone)
	else:
		InputMap.action_set_deadzone(action_name, deadzone)
		InputMap.action_erase_events(action_name)
	for event in events:
		InputMap.action_add_event(action_name, event)

	return success({
		"action": action_name,
		"deadzone": deadzone,
		"events_count": events.size(),
		"saved": true,
	})


func _serialize_event(event: InputEvent) -> Dictionary:
	if event is InputEventKey:
		var key_event: InputEventKey = event
		var info := {
			"type": "key",
			"keycode": OS.get_keycode_string(key_event.keycode) if key_event.keycode != KEY_NONE else "",
			"physical_keycode": OS.get_keycode_string(key_event.physical_keycode) if key_event.physical_keycode != KEY_NONE else "",
		}
		if key_event.ctrl_pressed: info["ctrl"] = true
		if key_event.shift_pressed: info["shift"] = true
		if key_event.alt_pressed: info["alt"] = true
		if key_event.meta_pressed: info["meta"] = true
		return info
	elif event is InputEventMouseButton:
		var mb_event: InputEventMouseButton = event
		return {
			"type": "mouse_button",
			"button_index": mb_event.button_index,
		}
	elif event is InputEventJoypadButton:
		var jb_event: InputEventJoypadButton = event
		return {
			"type": "joypad_button",
			"button_index": jb_event.button_index,
		}
	elif event is InputEventJoypadMotion:
		var jm_event: InputEventJoypadMotion = event
		return {
			"type": "joypad_motion",
			"axis": jm_event.axis,
			"axis_value": jm_event.axis_value,
		}
	return {"type": event.get_class()}


func _parse_event(def: Dictionary) -> InputEvent:
	var type: String = def.get("type", "")
	match type:
		"key":
			var event := InputEventKey.new()
			var keycode_str: String = def.get("keycode", "")
			if not keycode_str.is_empty():
				event.keycode = OS.find_keycode_from_string(keycode_str)
			var phys_str: String = def.get("physical_keycode", "")
			if not phys_str.is_empty():
				event.physical_keycode = OS.find_keycode_from_string(phys_str)
			event.ctrl_pressed = def.get("ctrl", false)
			event.shift_pressed = def.get("shift", false)
			event.alt_pressed = def.get("alt", false)
			event.meta_pressed = def.get("meta", false)
			return event
		"mouse_button":
			var event := InputEventMouseButton.new()
			event.button_index = int(def.get("button_index", 1))
			return event
		"joypad_button":
			var event := InputEventJoypadButton.new()
			event.button_index = int(def.get("button_index", 0))
			return event
		"joypad_motion":
			var event := InputEventJoypadMotion.new()
			event.axis = int(def.get("axis", 0))
			event.axis_value = float(def.get("axis_value", 1.0))
			return event
	return null
