@tool
extends "res://addons/godot_mcp/commands/base_command.gd"


func get_commands() -> Dictionary:
	return {
		"create_theme": _create_theme,
		"set_theme_color": _set_theme_color,
		"set_theme_constant": _set_theme_constant,
		"set_theme_font_size": _set_theme_font_size,
		"set_theme_stylebox": _set_theme_stylebox,
		"setup_control": _setup_control,
		"get_theme_info": _get_theme_info,
	}


func _create_theme(params: Dictionary) -> Dictionary:
	var result := require_string(params, "path")
	if result[1] != null:
		return result[1]
	var path: String = result[0]

	var theme := Theme.new()

	# Optionally set default font size
	var font_size: int = optional_int(params, "default_font_size", 0)
	if font_size > 0:
		theme.default_font_size = font_size

	var scene_guard := guard_offline_scene_save(path)
	if scene_guard != null:
		return scene_guard

	var err := ResourceSaver.save(theme, path)
	if err != OK:
		return error_internal("Failed to save theme: %s" % error_string(err))

	EditorInterface.get_resource_filesystem().scan()
	return success({"path": path, "created": true})


func _set_theme_color(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var result2 := require_string(params, "name")
	if result2[1] != null:
		return result2[1]
	var color_name: String = result2[0]

	var result3 := require_string(params, "color")
	if result3[1] != null:
		return result3[1]
	var color_str: String = result3[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node
	var color := Color(color_str)

	var theme_type: String = optional_string(params, "theme_type", "")
	if theme_type.is_empty():
		theme_type = control.get_class()

	var had_old := control.has_theme_color_override(color_name)
	var old_value: Variant = control.get("theme_override_colors/" + color_name) if had_old else null
	var undo_redo := get_undo_redo()
	undo_redo.create_action("MCP: Set theme color override")
	undo_redo.add_do_method(control, "add_theme_color_override", color_name, color)
	undo_redo.add_undo_method(self, "_restore_theme_override", control, "color", color_name, had_old, old_value)
	undo_redo.commit_action()

	return success({"node_path": node_path, "name": color_name, "color": color_str})


func _set_theme_constant(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var result2 := require_string(params, "name")
	if result2[1] != null:
		return result2[1]
	var const_name: String = result2[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node
	var value: int = int(params.get("value", 0))

	var had_old := control.has_theme_constant_override(const_name)
	var old_value: Variant = control.get("theme_override_constants/" + const_name) if had_old else null
	var undo_redo := get_undo_redo()
	undo_redo.create_action("MCP: Set theme constant override")
	undo_redo.add_do_method(control, "add_theme_constant_override", const_name, value)
	undo_redo.add_undo_method(self, "_restore_theme_override", control, "constant", const_name, had_old, old_value)
	undo_redo.commit_action()

	return success({"node_path": node_path, "name": const_name, "value": value})


func _set_theme_font_size(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var result2 := require_string(params, "name")
	if result2[1] != null:
		return result2[1]
	var font_name: String = result2[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node
	var size: int = int(params.get("size", 16))

	var had_old := control.has_theme_font_size_override(font_name)
	var old_value: Variant = control.get("theme_override_font_sizes/" + font_name) if had_old else null
	var undo_redo := get_undo_redo()
	undo_redo.create_action("MCP: Set theme font size override")
	undo_redo.add_do_method(control, "add_theme_font_size_override", font_name, size)
	undo_redo.add_undo_method(self, "_restore_theme_override", control, "font_size", font_name, had_old, old_value)
	undo_redo.commit_action()

	return success({"node_path": node_path, "name": font_name, "size": size})


func _set_theme_stylebox(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var result2 := require_string(params, "name")
	if result2[1] != null:
		return result2[1]
	var style_name: String = result2[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node

	var stylebox := StyleBoxFlat.new()

	var bg_color: String = optional_string(params, "bg_color", "")
	if not bg_color.is_empty():
		stylebox.bg_color = Color(bg_color)

	var border_color: String = optional_string(params, "border_color", "")
	if not border_color.is_empty():
		stylebox.border_color = Color(border_color)

	var border_width: int = optional_int(params, "border_width", 0)
	if border_width > 0:
		stylebox.border_width_left = border_width
		stylebox.border_width_top = border_width
		stylebox.border_width_right = border_width
		stylebox.border_width_bottom = border_width

	var corner_radius: int = optional_int(params, "corner_radius", 0)
	if corner_radius > 0:
		stylebox.corner_radius_top_left = corner_radius
		stylebox.corner_radius_top_right = corner_radius
		stylebox.corner_radius_bottom_left = corner_radius
		stylebox.corner_radius_bottom_right = corner_radius

	var padding: int = optional_int(params, "padding", 0)
	if padding > 0:
		stylebox.content_margin_left = padding
		stylebox.content_margin_top = padding
		stylebox.content_margin_right = padding
		stylebox.content_margin_bottom = padding

	var had_old := control.has_theme_stylebox_override(style_name)
	var old_value: Variant = control.get("theme_override_styles/" + style_name) if had_old else null
	var undo_redo := get_undo_redo()
	undo_redo.create_action("MCP: Set theme stylebox override")
	undo_redo.add_do_method(control, "add_theme_stylebox_override", style_name, stylebox)
	undo_redo.add_do_reference(stylebox)
	undo_redo.add_undo_method(self, "_restore_theme_override", control, "stylebox", style_name, had_old, old_value)
	if old_value is Resource:
		undo_redo.add_undo_reference(old_value)
	undo_redo.commit_action()

	return success({"node_path": node_path, "name": style_name, "type": "StyleBoxFlat"})


func _setup_control(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node
	var applied: Array = []
	var old_state := _capture_control_setup_state(control)
	var target: Control = control.duplicate() as Control

	# Anchor preset
	var anchor_preset: String = optional_string(params, "anchor_preset", "")
	if not anchor_preset.is_empty():
		var preset_map := {
			"top_left": Control.PRESET_TOP_LEFT,
			"top_right": Control.PRESET_TOP_RIGHT,
			"bottom_left": Control.PRESET_BOTTOM_LEFT,
			"bottom_right": Control.PRESET_BOTTOM_RIGHT,
			"center_left": Control.PRESET_CENTER_LEFT,
			"center_top": Control.PRESET_CENTER_TOP,
			"center_right": Control.PRESET_CENTER_RIGHT,
			"center_bottom": Control.PRESET_CENTER_BOTTOM,
			"center": Control.PRESET_CENTER,
			"left_wide": Control.PRESET_LEFT_WIDE,
			"top_wide": Control.PRESET_TOP_WIDE,
			"right_wide": Control.PRESET_RIGHT_WIDE,
			"bottom_wide": Control.PRESET_BOTTOM_WIDE,
			"vcenter_wide": Control.PRESET_VCENTER_WIDE,
			"hcenter_wide": Control.PRESET_HCENTER_WIDE,
			"full_rect": Control.PRESET_FULL_RECT,
		}
		if preset_map.has(anchor_preset):
			target.set_anchors_and_offsets_preset(preset_map[anchor_preset])
			applied.append("anchor_preset=%s" % anchor_preset)

	# Min size
	var min_size_str: String = optional_string(params, "min_size", "")
	if not min_size_str.is_empty():
		var expr := Expression.new()
		if expr.parse(min_size_str) == OK:
			var val = expr.execute()
			if val is Vector2:
				target.custom_minimum_size = val
				applied.append("min_size=%s" % min_size_str)

	# Size flags horizontal
	var sf_h: String = optional_string(params, "size_flags_h", "")
	if not sf_h.is_empty():
		var flags_map := {
			"fill": Control.SIZE_FILL,
			"expand": Control.SIZE_EXPAND,
			"fill_expand": Control.SIZE_EXPAND_FILL,
			"shrink_center": Control.SIZE_SHRINK_CENTER,
			"shrink_end": Control.SIZE_SHRINK_END,
		}
		if flags_map.has(sf_h):
			target.size_flags_horizontal = flags_map[sf_h]
			applied.append("size_flags_h=%s" % sf_h)

	# Size flags vertical
	var sf_v: String = optional_string(params, "size_flags_v", "")
	if not sf_v.is_empty():
		var flags_map := {
			"fill": Control.SIZE_FILL,
			"expand": Control.SIZE_EXPAND,
			"fill_expand": Control.SIZE_EXPAND_FILL,
			"shrink_center": Control.SIZE_SHRINK_CENTER,
			"shrink_end": Control.SIZE_SHRINK_END,
		}
		if flags_map.has(sf_v):
			target.size_flags_vertical = flags_map[sf_v]
			applied.append("size_flags_v=%s" % sf_v)

	# Margins (for MarginContainer)
	if params.has("margins") and params["margins"] is Dictionary:
		var margins: Dictionary = params["margins"]
		if target is MarginContainer:
			if margins.has("left"):
				target.add_theme_constant_override("margin_left", int(margins["left"]))
			if margins.has("top"):
				target.add_theme_constant_override("margin_top", int(margins["top"]))
			if margins.has("right"):
				target.add_theme_constant_override("margin_right", int(margins["right"]))
			if margins.has("bottom"):
				target.add_theme_constant_override("margin_bottom", int(margins["bottom"]))
			applied.append("margins=%s" % str(margins))

	# Separation (for VBox/HBoxContainer)
	if params.has("separation"):
		var sep: int = int(params["separation"])
		if target is BoxContainer:
			target.add_theme_constant_override("separation", sep)
			applied.append("separation=%d" % sep)

	# Grow direction horizontal
	var grow_h: String = optional_string(params, "grow_h", "")
	if not grow_h.is_empty():
		var grow_map := {
			"begin": Control.GROW_DIRECTION_BEGIN,
			"end": Control.GROW_DIRECTION_END,
			"both": Control.GROW_DIRECTION_BOTH,
		}
		if grow_map.has(grow_h):
			target.grow_horizontal = grow_map[grow_h]
			applied.append("grow_h=%s" % grow_h)

	# Grow direction vertical
	var grow_v: String = optional_string(params, "grow_v", "")
	if not grow_v.is_empty():
		var grow_map := {
			"begin": Control.GROW_DIRECTION_BEGIN,
			"end": Control.GROW_DIRECTION_END,
			"both": Control.GROW_DIRECTION_BOTH,
		}
		if grow_map.has(grow_v):
			target.grow_vertical = grow_map[grow_v]
			applied.append("grow_v=%s" % grow_v)

	if not applied.is_empty():
		var new_state := _capture_control_setup_state(target)
		_register_control_setup_undo(control, old_state, new_state)
	target.free()
	return success({"node_path": node_path, "applied": applied, "count": applied.size()})


func _restore_theme_override(control: Control, kind: String, override_name: String, had_old: bool, old_value: Variant) -> void:
	match kind:
		"color":
			if had_old:
				control.add_theme_color_override(override_name, old_value)
			else:
				control.remove_theme_color_override(override_name)
		"constant":
			if had_old:
				control.add_theme_constant_override(override_name, old_value)
			else:
				control.remove_theme_constant_override(override_name)
		"font_size":
			if had_old:
				control.add_theme_font_size_override(override_name, old_value)
			else:
				control.remove_theme_font_size_override(override_name)
		"stylebox":
			if had_old:
				control.add_theme_stylebox_override(override_name, old_value)
			else:
				control.remove_theme_stylebox_override(override_name)


func _capture_control_setup_state(control: Control) -> Dictionary:
	var state := {"properties": {}, "theme_constants": {}}
	for property: String in [
		"anchor_left", "anchor_top", "anchor_right", "anchor_bottom",
		"offset_left", "offset_top", "offset_right", "offset_bottom",
		"custom_minimum_size", "size_flags_horizontal", "size_flags_vertical",
		"grow_horizontal", "grow_vertical",
	]:
		state["properties"][property] = control.get(property)
	for constant_name: String in ["margin_left", "margin_top", "margin_right", "margin_bottom", "separation"]:
		var had_override := control.has_theme_constant_override(constant_name)
		state["theme_constants"][constant_name] = {
			"had": had_override,
			"value": control.get("theme_override_constants/" + constant_name) if had_override else null,
		}
	return state


func _register_control_setup_undo(control: Control, old_state: Dictionary, new_state: Dictionary) -> void:
	var undo_redo := get_undo_redo()
	undo_redo.create_action("MCP: Setup Control")
	for property: String in new_state["properties"]:
		undo_redo.add_do_property(control, property, new_state["properties"][property])
		undo_redo.add_undo_property(control, property, old_state["properties"][property])
	for constant_name: String in new_state["theme_constants"]:
		var new_constant: Dictionary = new_state["theme_constants"][constant_name]
		var old_constant: Dictionary = old_state["theme_constants"][constant_name]
		undo_redo.add_do_method(self, "_restore_theme_override", control, "constant", constant_name, new_constant["had"], new_constant["value"])
		undo_redo.add_undo_method(self, "_restore_theme_override", control, "constant", constant_name, old_constant["had"], old_constant["value"])
	undo_redo.commit_action()


func _get_theme_info(params: Dictionary) -> Dictionary:
	var result := require_string(params, "node_path")
	if result[1] != null:
		return result[1]
	var node_path: String = result[0]

	var node := find_node_by_path(node_path)
	if node == null or not (node is Control):
		return error_not_found("Control node at '%s'" % node_path)

	var control: Control = node
	var info := {"node_path": node_path, "class": control.get_class()}

	# Check if node has a theme
	var theme := control.theme
	if theme:
		info["theme_path"] = theme.resource_path
		info["type_list"] = Array(theme.get_type_list())

	# List overrides
	var overrides := {"colors": {}, "constants": {}, "font_sizes": {}, "styleboxes": {}}
	for prop in control.get_property_list():
		var pname: String = prop["name"]
		if pname.begins_with("theme_override_colors/"):
			var key := pname.substr(22)
			overrides["colors"][key] = "#" + (control.get(pname) as Color).to_html()
		elif pname.begins_with("theme_override_constants/"):
			var key := pname.substr(25)
			overrides["constants"][key] = control.get(pname)
		elif pname.begins_with("theme_override_font_sizes/"):
			var key := pname.substr(26)
			overrides["font_sizes"][key] = control.get(pname)
		elif pname.begins_with("theme_override_styles/"):
			var key := pname.substr(22)
			var style = control.get(pname)
			overrides["styleboxes"][key] = style.get_class() if style else null

	info["overrides"] = overrides
	return success(info)
