@tool
extends VBoxContainer

var websocket_server: Node = null
var command_router: Node = null

const MAX_LOG_ENTRIES := 200
const COLOR_CONNECTED := Color(0.2, 0.9, 0.2)
const COLOR_DISCONNECTED := Color(0.9, 0.2, 0.2)
const COLOR_STALE := Color(1.0, 0.7, 0.2)
const COLOR_SUCCESS := Color(0.6, 1, 0.6)
const COLOR_ERROR := Color(1, 0.6, 0.6)
const COLOR_DIM := Color(0.6, 0.6, 0.6)

const BASE_PORT := 6505
const MAX_PORT := 6509

# Header
var _status_icon: Label
var _status_label: Label
var _client_count_label: Label

# Tabs
var _tab_container: TabContainer

# Activity tab
var _show_details_check: CheckBox
var _log_container: VBoxContainer
var _log_scroll: ScrollContainer

# Clients tab
var _port_labels: Dictionary = {}  # port -> {icon: Label, label: Label}

# Tools tab
var _filter_edit: LineEdit
var _tools_container: VBoxContainer
var _tool_checkboxes: Dictionary = {}  # method_name -> CheckBox


func _ready() -> void:
	_build_ui()


func setup(ws_server: Node, cmd_router: Node = null) -> void:
	websocket_server = ws_server
	command_router = cmd_router

	if websocket_server:
		websocket_server.client_connected.connect(_on_client_connected)
		websocket_server.client_disconnected.connect(_on_client_disconnected)
		if websocket_server.has_signal("command_completed"):
			websocket_server.command_completed.connect(_on_command_completed)
		else:
			websocket_server.command_executed.connect(_on_command_executed)

	if command_router:
		_populate_tools_list()


func _build_ui() -> void:
	# Header bar
	var header := HBoxContainer.new()
	add_child(header)

	_status_icon = Label.new()
	_status_icon.text = "●"
	_status_icon.add_theme_color_override("font_color", COLOR_DISCONNECTED)
	header.add_child(_status_icon)

	_status_label = Label.new()
	_status_label.text = " MCP Pro: Waiting for connection..."
	header.add_child(_status_label)

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

	_client_count_label = Label.new()
	_client_count_label.text = "Clients: 0"
	header.add_child(_client_count_label)

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

	# TabContainer
	_tab_container = TabContainer.new()
	_tab_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
	add_child(_tab_container)

	_build_activity_tab()
	_build_clients_tab()
	_build_tools_tab()


func _build_activity_tab() -> void:
	var vbox := VBoxContainer.new()
	vbox.name = "Activity"
	vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL
	_tab_container.add_child(vbox)

	# Controls row
	var controls := HBoxContainer.new()
	vbox.add_child(controls)

	_show_details_check = CheckBox.new()
	_show_details_check.text = "Show Response Details"
	_show_details_check.button_pressed = false
	_show_details_check.toggled.connect(_on_show_details_toggled)
	controls.add_child(_show_details_check)

	var ctrl_spacer := Control.new()
	ctrl_spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	controls.add_child(ctrl_spacer)

	var clear_btn := Button.new()
	clear_btn.text = "Clear"
	clear_btn.pressed.connect(_on_clear_log)
	controls.add_child(clear_btn)

	# Log scroll
	_log_scroll = ScrollContainer.new()
	_log_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
	_log_scroll.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	_log_scroll.custom_minimum_size.y = 80
	vbox.add_child(_log_scroll)

	_log_container = VBoxContainer.new()
	_log_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	_log_scroll.add_child(_log_container)


func _build_clients_tab() -> void:
	var vbox := VBoxContainer.new()
	vbox.name = "Clients"
	_tab_container.add_child(vbox)

	for p in range(BASE_PORT, MAX_PORT + 1):
		var row := HBoxContainer.new()
		vbox.add_child(row)

		var icon := Label.new()
		icon.text = "○"
		icon.add_theme_color_override("font_color", COLOR_DISCONNECTED)
		row.add_child(icon)

		var lbl := Label.new()
		lbl.text = "  Port %d  —  Disconnected" % p
		row.add_child(lbl)

		_port_labels[p] = {"icon": icon, "label": lbl}


func _build_tools_tab() -> void:
	var vbox := VBoxContainer.new()
	vbox.name = "Tools"
	vbox.size_flags_vertical = Control.SIZE_EXPAND_FILL
	_tab_container.add_child(vbox)

	# Controls
	var controls := HBoxContainer.new()
	vbox.add_child(controls)

	_filter_edit = LineEdit.new()
	_filter_edit.placeholder_text = "Filter tools..."
	_filter_edit.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	_filter_edit.text_changed.connect(_on_filter_changed)
	controls.add_child(_filter_edit)

	var enable_all_btn := Button.new()
	enable_all_btn.text = "Enable All"
	enable_all_btn.pressed.connect(_on_enable_all)
	controls.add_child(enable_all_btn)

	var disable_all_btn := Button.new()
	disable_all_btn.text = "Disable All"
	disable_all_btn.pressed.connect(_on_disable_all)
	controls.add_child(disable_all_btn)

	# Scroll
	var scroll := ScrollContainer.new()
	scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
	scroll.custom_minimum_size.y = 80
	vbox.add_child(scroll)

	_tools_container = VBoxContainer.new()
	_tools_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	scroll.add_child(_tools_container)


func _populate_tools_list() -> void:
	if not command_router:
		return

	# Clear existing
	for child in _tools_container.get_children():
		child.queue_free()
	_tool_checkboxes.clear()

	var methods: Array = command_router.get_available_methods()
	methods.sort()

	for method_name: String in methods:
		var cb := CheckBox.new()
		cb.text = method_name
		cb.button_pressed = not command_router.is_tool_disabled(method_name)
		cb.toggled.connect(_on_tool_toggled.bind(method_name))
		_tools_container.add_child(cb)
		_tool_checkboxes[method_name] = cb


func _process(_delta: float) -> void:
	if not websocket_server:
		return

	var count: int = websocket_server.get_client_count()
	_client_count_label.text = "Clients: %d" % count

	var any_stale := false
	if websocket_server.has_method("is_port_stale"):
		for p in range(BASE_PORT, MAX_PORT + 1):
			if websocket_server.is_port_stale(p):
				any_stale = true
				break

	if count > 0:
		_status_icon.add_theme_color_override("font_color", COLOR_CONNECTED)
		_status_label.text = " MCP Pro: Connected"
	elif any_stale:
		_status_icon.add_theme_color_override("font_color", COLOR_STALE)
		_status_label.text = " MCP Pro: ⚠ Reconnecting (stale connection detected)..."
	else:
		_status_icon.add_theme_color_override("font_color", COLOR_DISCONNECTED)
		_status_label.text = " MCP Pro: Waiting for connection..."

	# Update clients tab
	_update_clients_tab()


func _update_clients_tab() -> void:
	var connected_ports: Array[int] = []
	if websocket_server.has_method("get_connected_ports"):
		connected_ports = websocket_server.get_connected_ports()

	for p: int in _port_labels:
		var info: Dictionary = _port_labels[p]
		var icon: Label = info["icon"]
		var lbl: Label = info["label"]

		var is_stale := false
		if websocket_server.has_method("is_port_stale"):
			is_stale = websocket_server.is_port_stale(p)

		if p in connected_ports:
			var time_str := ""
			if websocket_server.has_method("get_port_connect_time"):
				var elapsed: float = websocket_server.get_port_connect_time(p)
				if elapsed >= 0:
					var mins := int(elapsed) / 60
					var secs := int(elapsed) % 60
					time_str = "  (%dm %02ds)" % [mins, secs]

			var idle_str := ""
			if websocket_server.has_method("get_port_idle_time"):
				var idle: float = websocket_server.get_port_idle_time(p)
				if idle >= 2.0:
					idle_str = "  · idle %.0fs" % idle

			icon.text = "●"
			icon.add_theme_color_override("font_color", COLOR_CONNECTED)
			lbl.text = "  Port %d  —  Connected%s%s" % [p, time_str, idle_str]
		elif is_stale:
			icon.text = "◐"
			icon.add_theme_color_override("font_color", COLOR_STALE)
			lbl.text = "  Port %d  —  ⚠ Stale (reconnecting)" % p
		else:
			icon.text = "○"
			icon.add_theme_color_override("font_color", COLOR_DISCONNECTED)
			lbl.text = "  Port %d  —  Disconnected" % p


# --- Activity callbacks ---

func _on_client_connected() -> void:
	_add_log("Client connected", COLOR_CONNECTED)


func _on_client_disconnected() -> void:
	_add_log("Client disconnected", COLOR_DISCONNECTED)


func _on_command_executed(method: String, ok: bool) -> void:
	var color := COLOR_SUCCESS if ok else COLOR_ERROR
	var status_icon := "OK" if ok else "ERR"
	_add_log("[%s] %s" % [status_icon, method], color)


func _on_command_completed(method: String, ok: bool, response: String, source_port: int) -> void:
	var color := COLOR_SUCCESS if ok else COLOR_ERROR
	var status_icon := "OK" if ok else "ERR"
	_add_log("[%s] %s (port %d)" % [status_icon, method, source_port], color, response)


func _on_clear_log() -> void:
	for child in _log_container.get_children():
		child.queue_free()


func _on_show_details_toggled(on: bool) -> void:
	for entry in _log_container.get_children():
		if entry is VBoxContainer and entry.get_child_count() > 1:
			entry.get_child(1).visible = on


func _add_log(text: String, color: Color = Color.WHITE, response: String = "") -> void:
	if _log_container == null:
		return

	var entry := VBoxContainer.new()
	_log_container.add_child(entry)

	var label := Label.new()
	var time_str := Time.get_time_string_from_system()
	label.text = "[%s] %s" % [time_str, text]
	label.add_theme_color_override("font_color", color)
	label.add_theme_font_size_override("font_size", 12)
	entry.add_child(label)

	if not response.is_empty():
		var detail := RichTextLabel.new()
		var preview := response.substr(0, 500)
		if response.length() > 500:
			preview += "..."
		detail.text = preview
		detail.fit_content = true
		detail.scroll_active = false
		detail.add_theme_color_override("default_color", COLOR_DIM)
		detail.add_theme_font_size_override("normal_font_size", 11)
		detail.custom_minimum_size.y = 0
		detail.visible = _show_details_check.button_pressed if _show_details_check else false
		entry.add_child(detail)

	# Limit entries
	while _log_container.get_child_count() > MAX_LOG_ENTRIES:
		var old: Node = _log_container.get_child(0)
		_log_container.remove_child(old)
		old.queue_free()

	# Auto scroll to bottom
	_auto_scroll.call_deferred()


func _auto_scroll() -> void:
	if _log_scroll:
		_log_scroll.scroll_vertical = int(_log_scroll.get_v_scroll_bar().max_value)


# --- Tools callbacks ---

func _on_filter_changed(filter: String) -> void:
	for method_name: String in _tool_checkboxes:
		var cb: CheckBox = _tool_checkboxes[method_name]
		cb.visible = filter.is_empty() or method_name.containsn(filter)


func _on_tool_toggled(enabled: bool, method_name: String) -> void:
	if command_router and command_router.has_method("set_tool_disabled"):
		command_router.set_tool_disabled(method_name, not enabled)


func _on_enable_all() -> void:
	if command_router and command_router.has_method("set_all_tools_disabled"):
		command_router.set_all_tools_disabled(false)
	for method_name: String in _tool_checkboxes:
		_tool_checkboxes[method_name].set_pressed_no_signal(true)


func _on_disable_all() -> void:
	if command_router and command_router.has_method("set_all_tools_disabled"):
		command_router.set_all_tools_disabled(true)
	for method_name: String in _tool_checkboxes:
		_tool_checkboxes[method_name].set_pressed_no_signal(false)
