extends Node
## GameInspect / H5 Game AI Copilot — Godot Web 桥接 Autoload
##
## 用法：
## 1. 复制本文件到 Godot 项目（如 res://game_inspect_bridge.gd）
## 2. 项目 → 项目设置 → Autoload → 添加 Node 名 GameInspectBridge
## 3. Web 导出后刷新页面，DevTools 面板即可显示场景树
##
## 也可在「导出 → Web → Head Include」加入：
## <script src="https://your-cdn/game_inspect_bridge.js"></script> （无需，扩展会自动注入 JS 桥）

const SYNC_INTERVAL := 0.35

var _accum := 0.0
var _enabled := false


func _ready() -> void:
	if not OS.has_feature("web"):
		return
	_enabled = true
	_notify_js_connected()


func _process(delta: float) -> void:
	if not _enabled:
		return
	_accum += delta
	if _accum < SYNC_INTERVAL:
		return
	_accum = 0.0
	_push_snapshot()
	_apply_js_commands()


func _notify_js_connected() -> void:
	var info := {
		"version": Engine.get_version_info().get("string", "Godot"),
		"engineVersion": Engine.get_version_info().get("string", "Godot")
	}
	_js_eval("window.__H5_GAME_COPILOT_GODOT__ && window.__H5_GAME_COPILOT_GODOT__.onBridgeConnected(%s)" % [JSON.stringify(info)])


func _push_snapshot() -> void:
	var root := get_tree().root
	if root == null:
		return
	var data := _serialize_node(root)
	data["version"] = Engine.get_version_info().get("string", "Godot")
	_js_eval("window.__H5_GAME_COPILOT_GODOT__ && window.__H5_GAME_COPILOT_GODOT__.applySnapshot(%s)" % [JSON.stringify(JSON.stringify(data))])


func _serialize_node(node: Node) -> Dictionary:
	var item := {
		"godotId": node.get_instance_id(),
		"name": node.name,
		"type": node.get_class(),
		"path": str(node.get_path()),
		"visible": _node_visible(node),
		"props": _collect_props(node),
		"children": []
	}
	for child in node.get_children():
		item["children"].append(_serialize_node(child))
	return item


func _node_visible(node: Node) -> bool:
	if node is CanvasItem:
		return node.visible
	if node is Node3D:
		return node.visible
	return node.process_mode != Node.PROCESS_MODE_DISABLED


func _collect_props(node: Node) -> Dictionary:
	var props := {
		"name": node.name,
		"path": str(node.get_path()),
		"visible": _node_visible(node)
	}
	if node is CanvasItem:
		props["modulate"] = node.modulate
		props["position"] = node.position
		props["rotation"] = node.rotation
		props["scale"] = node.scale
		props["z_index"] = node.z_index
	elif node is Node3D:
		props["position"] = node.position
		props["rotation"] = node.rotation
		props["scale"] = node.scale
		props["visible"] = node.visible
	if node is Label:
		props["text"] = (node as Label).text
	elif node is RichTextLabel:
		props["text"] = (node as RichTextLabel).text
	return props


func _apply_js_commands() -> void:
	var raw := _js_eval("window.__H5_GAME_COPILOT_GODOT__ ? JSON.stringify(window.__H5_GAME_COPILOT_GODOT__.drainCommands()) : '[]'")
	if raw == null or str(raw) == "":
		return
	var parsed = JSON.parse_string(str(raw))
	if typeof(parsed) != TYPE_ARRAY:
		return
	for cmd in parsed:
		if typeof(cmd) != TYPE_DICTIONARY:
			continue
		match str(cmd.get("type", "")):
			"setProp":
				_apply_set_prop(int(cmd.get("nodeId", 0)), str(cmd.get("key", "")), cmd.get("value"))
			"highlight":
				_apply_highlight(int(cmd.get("nodeId", 0)))
			"pick":
				_apply_pick(float(cmd.get("x", 0)), float(cmd.get("y", 0)))


func _apply_set_prop(node_id: int, key: String, value: Variant) -> void:
	var node := instance_from_id(node_id)
	if node == null or not (node is Node):
		return
	if key == "visible":
		if node is CanvasItem:
			node.visible = bool(value)
		elif node is Node3D:
			node.visible = bool(value)
	elif key == "name" and node is Node:
		node.name = str(value)
	elif key == "position" and (node is CanvasItem or node is Node3D):
		node.position = value
	elif key == "rotation" and (node is CanvasItem or node is Node3D):
		node.rotation = float(value)
	elif key == "scale" and (node is CanvasItem or node is Node3D):
		node.scale = value
	elif key == "text" and "text" in node:
		node.set("text", str(value))
	elif key in node:
		node.set(key, value)


func _apply_highlight(node_id: int) -> void:
	var node := instance_from_id(node_id)
	if node == null or not (node is CanvasItem):
		return
	# 简单闪烁提示
	var tween := create_tween()
	var ci := node as CanvasItem
	var base := ci.modulate
	tween.tween_property(ci, "modulate", Color(0.2, 1.0, 0.4, 1.0), 0.12)
	tween.tween_property(ci, "modulate", base, 0.12)


func _apply_pick(x: float, y: float) -> void:
	var picked_id := 0
	var root := get_tree().root
	if root:
		var global_pos := Vector2(x, y)
		var node := _pick_control_at(root, global_pos)
		if node:
			picked_id = node.get_instance_id()
	_js_eval("window.__H5_GAME_COPILOT_GODOT__ && window.__H5_GAME_COPILOT_GODOT__.reportPick(%d)" % picked_id)


func _pick_control_at(node: Node, global_pos: Vector2) -> Node:
	for i in range(node.get_child_count() - 1, -1, -1):
		var child := node.get_child(i)
		var hit := _pick_control_at(child, global_pos)
		if hit:
			return hit
	if node is Control and (node as Control).visible:
		var ctrl := node as Control
		if ctrl.get_global_rect().has_point(global_pos):
			return node
	return null


func _js_eval(code: String) -> Variant:
	if not OS.has_feature("web"):
		return null
	return JavaScriptBridge.eval(code, true)
