extends Node
## Runtime debug panel. Toggle with F1.
## Reads DP.get_all() to build controls — adding a param to DP is all that's needed to show it here.

var _panel: Control
var _status_label: Label
var _prev_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_CAPTURED


func _ready() -> void:
	_build_ui()


func _build_ui() -> void:
	var canvas := CanvasLayer.new()
	canvas.layer = 128
	add_child(canvas)

	_panel = PanelContainer.new()
	_panel.anchor_left   = 1.0
	_panel.anchor_right  = 1.0
	_panel.anchor_top    = 0.0
	_panel.anchor_bottom = 1.0
	_panel.offset_left   = -390.0
	_panel.offset_right  = 0.0
	_panel.offset_top    = 0.0
	_panel.offset_bottom = 0.0
	_panel.mouse_filter  = Control.MOUSE_FILTER_STOP
	_panel.visible       = false

	var bg := StyleBoxFlat.new()
	bg.bg_color = Color(0.08, 0.08, 0.10, 0.95)
	_panel.add_theme_stylebox_override("panel", bg)
	canvas.add_child(_panel)

	var root_vbox := VBoxContainer.new()
	root_vbox.size_flags_horizontal = Control.SIZE_FILL
	_panel.add_child(root_vbox)

	# ── Toolbar ───────────────────────────────────────────────────────────────
	var toolbar_margin := MarginContainer.new()
	toolbar_margin.add_theme_constant_override("margin_left",   8)
	toolbar_margin.add_theme_constant_override("margin_right",  8)
	toolbar_margin.add_theme_constant_override("margin_top",    6)
	toolbar_margin.add_theme_constant_override("margin_bottom", 4)
	root_vbox.add_child(toolbar_margin)

	var toolbar := HBoxContainer.new()
	toolbar.add_theme_constant_override("separation", 6)
	toolbar_margin.add_child(toolbar)

	var title := Label.new()
	title.text = "DEBUG  [F1]"
	title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	toolbar.add_child(title)

	_status_label = Label.new()
	_status_label.modulate = Color(0.4, 1.0, 0.5)
	toolbar.add_child(_status_label)

	var save_btn := Button.new()
	save_btn.text = "Save"
	save_btn.pressed.connect(_on_save)
	toolbar.add_child(save_btn)

	var rand_all_btn := Button.new()
	rand_all_btn.text = "Randomize All"
	rand_all_btn.pressed.connect(_on_randomize_all)
	toolbar.add_child(rand_all_btn)

	var reset_btn := Button.new()
	reset_btn.text = "Reset All"
	reset_btn.pressed.connect(DP.reset_all)
	toolbar.add_child(reset_btn)

	root_vbox.add_child(HSeparator.new())

	# ── Scrollable content ────────────────────────────────────────────────────
	var scroll := ScrollContainer.new()
	scroll.size_flags_vertical   = Control.SIZE_EXPAND_FILL
	scroll.size_flags_horizontal = Control.SIZE_FILL
	root_vbox.add_child(scroll)

	var content_margin := MarginContainer.new()
	content_margin.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	content_margin.add_theme_constant_override("margin_left",   8)
	content_margin.add_theme_constant_override("margin_right",  8)
	content_margin.add_theme_constant_override("margin_top",    4)
	content_margin.add_theme_constant_override("margin_bottom", 8)
	scroll.add_child(content_margin)

	var content := VBoxContainer.new()
	content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	content_margin.add_child(content)

	_build_params(content)


func _build_params(content: VBoxContainer) -> void:
	# Group keys by section preserving registration order
	var sections: Dictionary = {}
	for key: String in DP.get_all():
		var sec: String = DP.get_all()[key]["section"]
		if not sections.has(sec):
			sections[sec] = []
		sections[sec].append(key)

	for section: String in sections:
		content.add_child(HSeparator.new())

		var header := Label.new()
		header.text = section.to_upper()
		header.modulate = Color(0.75, 0.85, 1.0)
		content.add_child(header)

		for key: String in sections[section]:
			var meta: Dictionary = DP.get_all()[key]
			if meta["type"] == TYPE_FLOAT:
				_add_float_row(content, key, meta)


func _add_float_row(parent: VBoxContainer, key: String, meta: Dictionary) -> void:
	var row := HBoxContainer.new()
	row.size_flags_horizontal = Control.SIZE_FILL
	parent.add_child(row)

	var lbl := Label.new()
	lbl.text = key.replace("_", " ")
	lbl.custom_minimum_size.x = 140
	lbl.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
	row.add_child(lbl)

	var slider := HSlider.new()
	slider.min_value = meta["min"]
	slider.max_value = meta["max"]
	slider.step      = meta["step"]
	slider.value     = meta["value"]
	slider.size_flags_horizontal = Control.SIZE_EXPAND_FILL
	slider.custom_minimum_size.x = 60
	row.add_child(slider)

	var spin := SpinBox.new()
	spin.min_value = meta["min"]
	spin.max_value = meta["max"]
	spin.step      = meta["step"]
	spin.value     = meta["value"]
	spin.custom_minimum_size.x = 85
	row.add_child(spin)

	var rand_btn := Button.new()
	rand_btn.text = "🎲"
	rand_btn.tooltip_text = "Randomize"
	rand_btn.pressed.connect(func() -> void:
		var v := randf_range(meta["min"], meta["max"])
		v = snappedf(v, meta["step"])
		slider.value = v
	)
	row.add_child(rand_btn)

	# Slider → SpinBox + DP (use no_signal to avoid echo)
	slider.value_changed.connect(func(v: float) -> void:
		spin.set_value_no_signal(v)
		DP.set_value(key, v)
	)
	# SpinBox → Slider + DP
	spin.value_changed.connect(func(v: float) -> void:
		slider.set_value_no_signal(v)
		DP.set_value(key, v)
	)
	# External changes (reset, load) → sync both controls
	DP.any_changed.connect(func(changed_key: String, _val: Variant) -> void:
		if changed_key != key and changed_key != "__all__":
			return
		var v := DP.f(key)
		slider.set_value_no_signal(v)
		spin.set_value_no_signal(v)
	)



func _on_save() -> void:
	DP.save()
	_status_label.text = "Saved!"
	get_tree().create_timer(1.5).timeout.connect(func() -> void:
		_status_label.text = ""
	)




func _input(event: InputEvent) -> void:
	if _panel.visible and Input.is_key_pressed(KEY_CTRL) and event is InputEventMouseMotion:
		get_viewport().set_input_as_handled()


func _unhandled_input(event: InputEvent) -> void:
	if not (event is InputEventKey and event.pressed and not event.echo):
		return
	if (event as InputEventKey).keycode != KEY_F1:
		return
	_panel.visible = not _panel.visible
	if _panel.visible:
		_prev_mouse_mode = Input.mouse_mode
		Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
	else:
		Input.mouse_mode = _prev_mouse_mode
	get_viewport().set_input_as_handled()



func _on_randomize_all() -> void:
	for key: String in DP.get_all():
		var meta: Dictionary = DP.get_all()[key]
		if meta["type"] == TYPE_FLOAT:
			var v := snappedf(randf_range(meta["min"], meta["max"]), meta["step"])
			DP.set_value(key, v)
