@tool
extends Node

## Handles input simulation requests from the MCP bridge.
## Writes a command file that GolemCapture (in the running game) picks up,
## then polls for the done flag via a deferred response.

const INPUT_SEQUENCE_PATH := "user://golem_input_sequence.json"
const INPUT_DONE_PATH := "user://golem_input_done.json"


func register(server: Node) -> void:
	server.register_handler("simulate_input", _simulate_input)


func _simulate_input(args: Dictionary) -> Dictionary:
	if not EditorInterface.is_playing_scene():
		return {"ok": false, "error": "No scene is running. Use play_scene first."}

	if not ProjectSettings.has_setting("autoload/GolemCapture"):
		return {"ok": false, "error": "GolemCapture autoload is not registered. Input simulation requires GolemCapture. Re-enable the Golem MCP plugin or run the installer again."}

	var sequence: Array = args.get("sequence", [])
	if sequence.is_empty():
		return {"ok": false, "error": "Empty sequence. Provide at least one step."}

	var loop_count: int = int(args.get("loop", 1))
	if loop_count < 1:
		loop_count = 1

	# Validate steps structure
	for i in range(sequence.size()):
		var step: Dictionary = sequence[i]
		if not step.has("action") and not step.has("wait"):
			return {"ok": false, "error": "Step %d: must have 'action' or 'wait' key" % i}

	# Calculate timeout: sum all durations/waits × loops + generous margin
	var total_duration: float = 0.0
	for step in sequence:
		if step.has("wait"):
			total_duration += float(step["wait"])
		elif step.has("duration"):
			total_duration += float(step["duration"])
		else:
			total_duration += 0.1  # toggle steps are near-instant
	total_duration *= loop_count
	var timeout: float = total_duration + 5.0  # 5s margin

	# Clean up stale files
	if FileAccess.file_exists(INPUT_DONE_PATH):
		DirAccess.remove_absolute(INPUT_DONE_PATH)

	# Write command file for GolemCapture to pick up
	var command := {"sequence": sequence, "loop": loop_count}
	var file := FileAccess.open(INPUT_SEQUENCE_PATH, FileAccess.WRITE)
	if file == null:
		return {"ok": false, "error": "Cannot write input sequence file"}
	file.store_string(JSON.stringify(command))
	file.close()

	# Return deferred response — poll for done flag
	return {
		"_deferred": true,
		"_check_fn": _check_input_done,
		"_timeout": timeout,
		"_timeout_msg": "Input simulation timed out after %.1fs" % timeout,
	}


func _check_input_done() -> Variant:
	if not FileAccess.file_exists(INPUT_DONE_PATH):
		return null

	var file := FileAccess.open(INPUT_DONE_PATH, FileAccess.READ)
	if file == null:
		return null

	var text := file.get_as_text()
	file.close()

	# Clean up done file
	DirAccess.remove_absolute(INPUT_DONE_PATH)

	var json := JSON.new()
	if json.parse(text) != OK:
		return {"ok": false, "error": "Invalid done file"}

	var data: Dictionary = json.data
	if data.get("ok", false):
		return {"ok": true, "type": "text", "result": data.get("message", "Input simulation complete")}
	else:
		return {"ok": false, "error": data.get("message", "Input simulation failed")}
