@tool
extends EditorPlugin

const AUTOLOAD_NAME := "GolemCapture"

const HANDLERS := {
	"screenshot_handler": preload("handlers/screenshot_handler.gd"),
	"scene_handler": preload("handlers/scene_handler.gd"),
	"inspect_handler": preload("handlers/inspect_handler.gd"),
	"run_handler": preload("handlers/run_handler.gd"),
	"script_handler": preload("handlers/script_handler.gd"),
	"project_handler": preload("handlers/project_handler.gd"),
	"input_handler": preload("handlers/input_handler.gd"),
	"theme_handler": preload("handlers/theme_handler.gd"),
}

var _server: GolemServer
var _bottom_panel: MarginContainer
var _bottom_button: Button
var _status_label: Label
var _clients_label: Label
var _requests_label: Label
var _pending_label: Label
var _activity_container: VBoxContainer
var _activity_rows: Array[Dictionary] = []
var _status_timer: Timer
var _icon_connected: ImageTexture
var _icon_disconnected: ImageTexture
var _icon_error: ImageTexture
var _error_flash_until: float = 0.0

const MAX_ACTIVITY_DISPLAY := 8


func _enter_tree() -> void:
	# Register game capture autoload
	if not ProjectSettings.has_setting("autoload/" + AUTOLOAD_NAME):
		var script_path := (get_script() as Script).resource_path.get_base_dir() + "/golem_capture.gd"
		add_autoload_singleton(AUTOLOAD_NAME, script_path)

	# Create TCP server
	_server = preload("golem_server.gd").new()
	_server.name = "GolemServer"
	add_child(_server)

	# Create and register all handlers
	for ref_name in HANDLERS:
		var handler: Node = HANDLERS[ref_name].new()
		handler.name = ref_name.to_pascal_case()
		_server.add_child(handler)
		_server.set(ref_name, handler)
		handler.register(_server)

	# Status indicator in bottom panel (next to Output / Debugger)
	_create_status_icons()
	_create_bottom_panel()
	_server.client_connected.connect(_update_status.unbind(1))
	_server.client_disconnected.connect(_update_status.unbind(1))
	_server.handler_error.connect(_on_handler_error)
	_update_status()

	print("Golem MCP: Plugin loaded — TCP server on port %d" % GolemServer.PORT)


func _exit_tree() -> void:
	if _status_timer:
		_status_timer.stop()
		_status_timer.queue_free()
		_status_timer = null

	if _bottom_panel:
		remove_control_from_bottom_panel(_bottom_panel)
		_bottom_panel.queue_free()
		_bottom_panel = null
	_bottom_button = null
	_activity_rows.clear()

	if _server:
		_server.stop()
		_server.queue_free()
		_server = null

	if ProjectSettings.has_setting("autoload/" + AUTOLOAD_NAME):
		remove_autoload_singleton(AUTOLOAD_NAME)

	print("Golem MCP: Plugin unloaded")


# ------------------------------------------------------------------
# Status icons (programmatic circle textures)
# ------------------------------------------------------------------

func _create_status_icons() -> void:
	_icon_connected = _make_circle_icon(Color(0.45, 0.80, 0.45))
	_icon_disconnected = _make_circle_icon(Color(0.45, 0.45, 0.45))
	_icon_error = _make_circle_icon(Color(0.95, 0.55, 0.20))


func _make_circle_icon(color: Color) -> ImageTexture:
	var s := 16
	var img := Image.create(s, s, false, Image.FORMAT_RGBA8)
	var center := Vector2(s / 2.0, s / 2.0)
	var radius := s / 2.0 - 1.0
	for x in range(s):
		for y in range(s):
			var dist := Vector2(x + 0.5, y + 0.5).distance_to(center)
			if dist <= radius:
				var edge := clampf(radius - dist, 0.0, 1.0)
				img.set_pixel(x, y, Color(color.r, color.g, color.b, color.a * edge))
			else:
				img.set_pixel(x, y, Color(0, 0, 0, 0))
	return ImageTexture.create_from_image(img)


# ------------------------------------------------------------------
# Bottom panel UI
# ------------------------------------------------------------------

func _create_bottom_panel() -> void:
	_bottom_panel = MarginContainer.new()
	_bottom_panel.add_theme_constant_override("margin_left", 10)
	_bottom_panel.add_theme_constant_override("margin_right", 10)
	_bottom_panel.add_theme_constant_override("margin_top", 6)
	_bottom_panel.add_theme_constant_override("margin_bottom", 6)

	var vbox := VBoxContainer.new()
	vbox.add_theme_constant_override("separation", 4)
	_bottom_panel.add_child(vbox)

	# --- Top status bar ---
	var status_bar := HBoxContainer.new()
	status_bar.add_theme_constant_override("separation", 16)
	vbox.add_child(status_bar)

	_status_label = Label.new()
	_status_label.text = "Waiting for connection..."
	status_bar.add_child(_status_label)

	_clients_label = Label.new()
	_clients_label.add_theme_color_override("font_color", Color(0.5, 0.5, 0.5))
	status_bar.add_child(_clients_label)

	_requests_label = Label.new()
	_requests_label.add_theme_color_override("font_color", Color(0.5, 0.5, 0.5))
	status_bar.add_child(_requests_label)

	_pending_label = Label.new()
	_pending_label.add_theme_color_override("font_color", Color(0.85, 0.75, 0.35))
	status_bar.add_child(_pending_label)

	var spacer := Control.new()
	spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	status_bar.add_child(spacer)

	var port_label := Label.new()
	port_label.text = "tcp://127.0.0.1:%d" % GolemServer.PORT
	port_label.add_theme_color_override("font_color", Color(0.4, 0.4, 0.4))
	status_bar.add_child(port_label)

	# --- Separator ---
	var sep := HSeparator.new()
	vbox.add_child(sep)

	# --- Activity log ---
	_activity_container = VBoxContainer.new()
	_activity_container.add_theme_constant_override("separation", 2)
	vbox.add_child(_activity_container)

	for i in range(MAX_ACTIVITY_DISPLAY):
		var row := HBoxContainer.new()
		row.add_theme_constant_override("separation", 8)
		row.visible = false
		_activity_container.add_child(row)

		var tool_label := Label.new()
		tool_label.add_theme_font_size_override("font_size", 12)
		row.add_child(tool_label)

		var row_spacer := Control.new()
		row_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
		row.add_child(row_spacer)

		var status_marker := Label.new()
		status_marker.add_theme_font_size_override("font_size", 11)
		row.add_child(status_marker)

		var duration_label := Label.new()
		duration_label.add_theme_font_size_override("font_size", 11)
		duration_label.add_theme_color_override("font_color", Color(0.4, 0.4, 0.4))
		duration_label.custom_minimum_size.x = 50
		row.add_child(duration_label)

		var time_label := Label.new()
		time_label.add_theme_font_size_override("font_size", 12)
		time_label.add_theme_color_override("font_color", Color(0.45, 0.45, 0.45))
		time_label.custom_minimum_size.x = 70
		time_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
		row.add_child(time_label)

		_activity_rows.append({
			"row": row,
			"tool": tool_label,
			"status": status_marker,
			"duration": duration_label,
			"time": time_label,
		})

	# Register bottom panel — returns the tab button
	_bottom_button = add_control_to_bottom_panel(_bottom_panel, "Golem")

	# Timer for periodic refresh
	_status_timer = Timer.new()
	_status_timer.wait_time = 2.0
	_status_timer.timeout.connect(_update_status)
	add_child(_status_timer)
	_status_timer.start()


# ------------------------------------------------------------------
# Status updates
# ------------------------------------------------------------------

func _on_handler_error(_tool_name: String) -> void:
	_error_flash_until = Time.get_unix_time_from_system() + 3.0
	_update_status()


func _update_status() -> void:
	if _server == null or _status_label == null:
		return

	var clients := _server.get_client_count()
	var requests := _server.get_request_count()
	var pending := _server.get_deferred_count()
	var now := Time.get_unix_time_from_system()

	# --- Top bar ---
	if clients > 0:
		_status_label.text = "Connected"
		_status_label.add_theme_color_override("font_color", Color(0.55, 0.85, 0.55))
		_clients_label.text = "%d client(s)" % clients
		_requests_label.text = "%d requests" % requests
	else:
		_status_label.text = "Waiting for connection..."
		_status_label.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6))
		_clients_label.text = ""
		_requests_label.text = ""

	# Pending deferred operations
	if pending > 0:
		_pending_label.text = "%d pending" % pending
	else:
		_pending_label.text = ""

	# --- Tab icon (error flash > connected > disconnected) ---
	if _bottom_button:
		if now < _error_flash_until:
			_bottom_button.icon = _icon_error
		elif clients > 0:
			_bottom_button.icon = _icon_connected
		else:
			_bottom_button.icon = _icon_disconnected

	# --- Activity log (newest first) ---
	var activity := _server.get_activity_log()
	for i in range(MAX_ACTIVITY_DISPLAY):
		var row_data: Dictionary = _activity_rows[i]
		var log_idx := activity.size() - 1 - i
		if log_idx >= 0:
			var entry: Dictionary = activity[log_idx]
			row_data["row"].visible = true
			row_data["tool"].text = entry["tool"]
			if entry["ok"]:
				row_data["tool"].add_theme_color_override("font_color", Color(0.75, 0.75, 0.75))
				row_data["status"].text = ""
			else:
				row_data["tool"].add_theme_color_override("font_color", Color(0.95, 0.55, 0.35))
				row_data["status"].text = "FAIL"
				row_data["status"].add_theme_color_override("font_color", Color(0.95, 0.55, 0.35))
			var dur: float = entry.get("duration", 0.0)
			if dur > 0.0:
				row_data["duration"].text = _format_duration(dur)
			else:
				row_data["duration"].text = ""
			row_data["time"].text = _format_time_ago(entry["time"], now)
		else:
			row_data["row"].visible = false


static func _format_duration(seconds: float) -> String:
	if seconds < 0.001:
		return ""
	if seconds < 1.0:
		return "%dms" % int(seconds * 1000.0)
	if seconds < 10.0:
		return "%.1fs" % seconds
	return "%ds" % int(seconds)


static func _format_time_ago(unix_time: float, now: float) -> String:
	var diff := now - unix_time
	if diff < 5.0:
		return "just now"
	elif diff < 60.0:
		return "%ds ago" % int(diff)
	elif diff < 3600.0:
		return "%dm ago" % int(diff / 60.0)
	else:
		return "%dh ago" % int(diff / 3600.0)
