## 法术编辑器停靠面板（@tool）— 策划/开发可视化新增·编辑·删除法术
## 数据持久化到 res://data/spells.json，游戏运行时由 SpellRegistry 加载
@tool
extends VBoxContainer

const DATA_PATH: String = "res://data/spells.json"
const TYPE_NAMES: Array = ["ACTION", "MODIFIER", "TRIGGER", "LOGIC"]

## meta 模板（按类型“插入模板”用）
const META_TEMPLATES: Dictionary = {
	0: '{ "base_damage": 5.0, "speed": 350.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "shop_cost": 20 }',
	1: '{ "damage_add": 10.0, "shop_cost": 20 }',
	2: '{ "base_damage": 3.0, "speed": 250.0, "lifetime": 4.0, "radius": 6.0, "damage_type": 0, "shop_cost": 30 }',
	3: '{ "logic_op": "every_n_shots", "n": 3, "reg": 0, "shop_cost": 24 }',
}

var _spells: Dictionary = {}     # { id: {type, display_name, description, element_tags, meta} }
var _cur_id: String = ""

# UI 引用
var _list: ItemList
var _id_edit: LineEdit
var _type_opt: OptionButton
var _name_edit: LineEdit
var _desc_edit: LineEdit
var _tags_edit: LineEdit
var _meta_edit: TextEdit
var _status: Label

func _ready() -> void:
	_build_ui()
	_load_data()
	_refresh_list()

func _build_ui() -> void:
	custom_minimum_size = Vector2(300, 400)
	add_theme_constant_override("separation", 4)

	var title := Label.new()
	title.text = "✨ 法术编辑器"
	title.add_theme_font_size_override("font_size", 16)
	add_child(title)

	# 法术列表
	_list = ItemList.new()
	_list.custom_minimum_size = Vector2(0, 120)
	_list.size_flags_vertical = Control.SIZE_EXPAND_FILL
	_list.item_selected.connect(_on_select)
	add_child(_list)

	var row := HBoxContainer.new()
	add_child(row)
	row.add_child(_btn("➕ 新增", _on_new))
	row.add_child(_btn("⧉ 复制", _on_dup))
	row.add_child(_btn("🗑 删除", _on_delete))

	add_child(HSeparator.new())

	# 表单
	_id_edit   = _field("ID（唯一）")
	_type_opt  = OptionButton.new()
	for n in TYPE_NAMES:
		_type_opt.add_item(n)
	_labeled("类型", _type_opt)
	_name_edit = _field("显示名（tr 键或文本）")
	_desc_edit = _field("描述（tr 键或文本）")
	_tags_edit = _field("元素标签（逗号分隔，如 tag:water）")

	var meta_lbl := Label.new()
	meta_lbl.text = "meta（JSON，因类型而异）"
	add_child(meta_lbl)
	_meta_edit = TextEdit.new()
	_meta_edit.custom_minimum_size = Vector2(0, 90)
	_meta_edit.placeholder_text = '{ "base_damage": 5.0, ... }'
	add_child(_meta_edit)
	add_child(_btn("插入该类型 meta 模板", _on_template))

	add_child(HSeparator.new())

	var save_row := HBoxContainer.new()
	add_child(save_row)
	save_row.add_child(_btn("✓ 应用到列表", _on_apply))
	save_row.add_child(_btn("💾 保存文件", _on_save_file))
	save_row.add_child(_btn("↻ 重载", func(): _load_data(); _refresh_list(); _set_status("已重载")))

	_status = Label.new()
	_status.add_theme_font_size_override("font_size", 11)
	_status.modulate = Color(0.6, 0.9, 0.6)
	add_child(_status)

func _btn(text: String, cb: Callable) -> Button:
	var b := Button.new()
	b.text = text
	b.pressed.connect(cb)
	return b

func _field(placeholder: String) -> LineEdit:
	var le := LineEdit.new()
	le.placeholder_text = placeholder
	add_child(le)
	return le

func _labeled(label: String, ctrl: Control) -> void:
	var l := Label.new()
	l.text = label
	add_child(l)
	add_child(ctrl)

# ── 数据 ────────────────────────────────────────────────────
func _load_data() -> void:
	_spells = {}
	if FileAccess.file_exists(DATA_PATH):
		var parsed = JSON.parse_string(FileAccess.get_file_as_string(DATA_PATH))
		if parsed is Dictionary:
			_spells = parsed

func _refresh_list() -> void:
	_list.clear()
	var ids: Array = _spells.keys()
	ids.sort()
	for sid in ids:
		var t: int = int(_spells[sid].get("type", 0))
		_list.add_item("[%s] %s" % [TYPE_NAMES[clampi(t, 0, 3)], sid])
		_list.set_item_metadata(_list.item_count - 1, sid)

func _on_select(idx: int) -> void:
	_cur_id = String(_list.get_item_metadata(idx))
	var d: Dictionary = _spells.get(_cur_id, {})
	_id_edit.text = _cur_id
	_type_opt.selected = clampi(int(d.get("type", 0)), 0, 3)
	_name_edit.text = String(d.get("display_name", ""))
	_desc_edit.text = String(d.get("description", ""))
	_tags_edit.text = ",".join(d.get("element_tags", []))
	_meta_edit.text = JSON.stringify(d.get("meta", {}), "  ")

func _on_apply() -> void:
	var sid: String = _id_edit.text.strip_edges()
	if sid == "":
		_set_status("✗ ID 不能为空", true); return
	var meta = JSON.parse_string(_meta_edit.text)
	if not (meta is Dictionary):
		_set_status("✗ meta 不是合法 JSON 对象", true); return
	var tags: Array = []
	for t in _tags_edit.text.split(",", false):
		var s: String = t.strip_edges()
		if s != "":
			tags.append(s)
	# 改了 ID：移除旧键
	if _cur_id != "" and _cur_id != sid and _spells.has(_cur_id):
		_spells.erase(_cur_id)
	_spells[sid] = {
		"type": _type_opt.selected,
		"display_name": _name_edit.text,
		"description": _desc_edit.text,
		"element_tags": tags,
		"meta": meta,
	}
	_cur_id = sid
	_refresh_list()
	_set_status("✓ 已应用『%s』到列表（记得保存文件）" % sid)

func _on_save_file() -> void:
	DirAccess.make_dir_recursive_absolute("res://data")
	var f := FileAccess.open(DATA_PATH, FileAccess.WRITE)
	if f:
		f.store_string(JSON.stringify(_spells, "  "))
		f.close()
		_set_status("💾 已保存 %d 条法术 → %s" % [_spells.size(), DATA_PATH])
	else:
		_set_status("✗ 写入失败", true)

func _on_new() -> void:
	var base := "new_spell"
	var sid := base
	var i := 1
	while _spells.has(sid):
		sid = "%s_%d" % [base, i]; i += 1
	_spells[sid] = {"type": 0, "display_name": sid, "description": "",
		"element_tags": [], "meta": JSON.parse_string(META_TEMPLATES[0])}
	_refresh_list()
	_select_id(sid)

func _on_dup() -> void:
	if _cur_id == "" or not _spells.has(_cur_id):
		return
	var sid := _cur_id + "_copy"
	var i := 1
	while _spells.has(sid):
		sid = "%s_copy%d" % [_cur_id, i]; i += 1
	_spells[sid] = _spells[_cur_id].duplicate(true)
	_refresh_list()
	_select_id(sid)

func _on_delete() -> void:
	if _cur_id != "" and _spells.has(_cur_id):
		_spells.erase(_cur_id)
		_cur_id = ""
		_refresh_list()
		_set_status("已删除（记得保存文件）")

func _on_template() -> void:
	_meta_edit.text = String(META_TEMPLATES.get(_type_opt.selected, "{}"))

func _select_id(sid: String) -> void:
	for i in _list.item_count:
		if String(_list.get_item_metadata(i)) == sid:
			_list.select(i)
			_on_select(i)
			return

func _set_status(msg: String, is_err: bool = false) -> void:
	if _status:
		_status.text = msg
		_status.modulate = Color(1.0, 0.5, 0.5) if is_err else Color(0.6, 0.9, 0.6)
