extends PanelContainer

@onready var avatar_type_combo: OptionButton = $VBoxContainer/MarginContainer/ToolBar/AvatarTypeCombo
@onready var avatar_part_combo: OptionButton = $VBoxContainer/MarginContainer/ToolBar/AvatarPartCombo
@onready var palette_combo: OptionButton = $VBoxContainer/MarginContainer/ToolBar/PaletteCombo

@onready var state_panel: VBoxContainer = $VBoxContainer/HSplitContainer/StatePanel
@onready var canvas_2d: Node2D = $VBoxContainer/HSplitContainer/HSplitContainer/VSplitContainer/PanelContainer/SubViewportContainer/SubViewport/Canvas2d
@onready var sub_viewport_container: SubViewportContainer = $VBoxContainer/HSplitContainer/HSplitContainer/VSplitContainer/PanelContainer/SubViewportContainer
@onready var asset_panel: PanelContainer = $VBoxContainer/HSplitContainer/HSplitContainer/VSplitContainer/PanelContainer2/AssetPanel
@onready var panel_container: PanelContainer = $VBoxContainer/HSplitContainer/HSplitContainer/VSplitContainer/PanelContainer

@onready var asset_line_edit: LineEdit = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/AssetLineEdit
@onready var layer_line_edit: LineEdit = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer/LayerLineEdit
@onready var layer_button: Button = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer/LayerButton
@onready var layer_offset_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/LayerOffsetSpinBox
@onready var position_x_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer2/PositionXSpinBox
@onready var position_y_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer2/PositionYSpinBox
@onready var rotation_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/RotationSpinBox
@onready var scale_x_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer4/ScaleXSpinBox
@onready var scale_y_spin_box: SpinBox = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer4/ScaleYSpinBox
@onready var popup_panel: PopupPanel = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer/LayerButton/PopupPanel
@onready var layer_selecter: Panel = $VBoxContainer/HSplitContainer/HSplitContainer/VBoxContainer2/PanelContainer2/MarginContainer/VBoxContainer/GridContainer/HBoxContainer/LayerButton/PopupPanel/LayerSelecter

var avatar_type: String = "Clothes"

var _current_part = null
var _current_state = null
var _current_elements = null
var _current_element_index = -1
var _current_element = null

func _ready() -> void:
	state_panel.avatar_type = avatar_type
	_init_gui()

func _init_gui():
	
	get_tree().get_root().files_dropped.connect(_on_files_dropped)
	visibility_changed.connect(_on_visibility_changed)
	
	avatar_type_combo.item_selected.connect(_on_avatar_type_combo_item_selected)
	
	sub_viewport_container.mouse_entered.connect(_on_canvas_mouse_entered)
	sub_viewport_container.mouse_exited.connect(_on_canvas_mouse_exited)
	canvas_2d.element_property_changed.connect(_on_canvas_element_property_changed)
	canvas_2d.element_selected.connect(_on_canvas_element_selected)
	canvas_2d.element_action.connect(_on_canvas_element_action, ConnectFlags.CONNECT_DEFERRED)
	canvas_2d.asset_drop.connect(_on_asset_dropped)
	asset_panel.asset_updated.connect(_on_asset_updated)
	avatar_part_combo.item_selected.connect(_on_avatar_part_combo_item_selected)
	state_panel.on_select_change.connect(_on_state_treeview_select_change)
	palette_combo.item_selected.connect(_on_palette_combo_item_selected)
	
	position_x_spin_box.value_changed.connect(_on_property_changed.bind("PositionX"))
	position_y_spin_box.value_changed.connect(_on_property_changed.bind("PositionY"))
	rotation_spin_box.value_changed.connect(_on_property_changed.bind("Rotation"))
	scale_x_spin_box.value_changed.connect(_on_property_changed.bind("ScaleX"))
	scale_y_spin_box.value_changed.connect(_on_property_changed.bind("ScaleY"))
	layer_button.pressed.connect(_on_layer_button_pressed)
	layer_selecter.pressed.connect(_on_layer_selecter_pressed)

func _on_visibility_changed() -> void:
	if is_visible_in_tree() == true:
		#load_data()
		update_data()
		canvas_2d.sync_background()
	else:
		canvas_2d.cancle_free_transform()

func load_data():
	if AvatarDollDataMgr.initialed == false or avatar_type not in AvatarDollDataMgr.avatar_doll_data:
		avatar_part_combo.clear()
		return
	
	avatar_part_combo.clear()
	var parts = AvatarDollDataMgr.avatar_doll_data[avatar_type]
	for part in parts:
		avatar_part_combo.add_item(part["Name"])
	
	if parts.size() > 0:
		avatar_part_combo.selected = 0
		_current_part = AvatarDollDataMgr.avatar_doll_data[avatar_type][0]
		
		palette_combo.clear()
		palette_combo.add_item("Default")
		for i in range(_current_part["Palettes"].size()):
			var palette = _current_part["Palettes"][i]
			palette_combo.add_item(palette["Name"])
	else:
		_current_part = null
		
	state_panel.set_avatar_type(0, true)
	update_data()
	pass

func update_data():
	if _current_part != null:
		var part_index = avatar_part_combo.selected
		_current_state = state_panel.current_state_code 
		_current_part = AvatarDollDataMgr.avatar_doll_data[avatar_type][part_index]
		_current_element = null
		_current_element_index = -1

		state_panel.set_avatar_type(part_index, false)
		if _current_state in _current_part["Elements"]:
			_current_elements = _current_part["Elements"][_current_state]
			canvas_2d.set_editable(true)
			canvas_2d.load_elements(_current_elements)
			
		elif _current_state != "":
			_current_elements = []
			_current_part["Elements"][_current_state] = _current_elements
			canvas_2d.set_editable(true)
			canvas_2d.load_elements(_current_elements)
			
		else:
			_current_elements = null
			canvas_2d.set_editable(false)
			canvas_2d.load_elements([])
			canvas_2d.zoom_fit()
			
		# palette
		palette_combo.clear()
		palette_combo.add_item("Default")
		for i in range(_current_part["Palettes"].size()):
			var palette = _current_part["Palettes"][i]
			palette_combo.add_item(palette["Name"])
			
		asset_panel.update_data()
	else:
		canvas_2d.load_elements([])
		canvas_2d.set_editable(false)

	update_property()
	pass
	
func update_property():
	if _current_element != null:
		asset_line_edit.text = AvatarDollDataMgr.get_asset_name(_current_element["AssetId"])
		layer_line_edit.text = str(_current_element["Layer"])
		layer_offset_spin_box.set_value_no_signal(_current_element["LayerOffset"])
		position_x_spin_box.set_value_no_signal(_current_element["PositionX"])
		position_y_spin_box.set_value_no_signal(_current_element["PositionY"])
		rotation_spin_box.set_value_no_signal(_current_element["Rotation"])
		scale_x_spin_box.set_value_no_signal(_current_element["ScaleX"])
		scale_y_spin_box.set_value_no_signal(_current_element["ScaleY"])
		
		layer_button.disabled = false
		layer_offset_spin_box.editable = true
		position_x_spin_box.editable = true
		position_y_spin_box.editable = true
		rotation_spin_box.editable = true
		scale_x_spin_box.editable = true
		scale_y_spin_box.editable = true
		
	else:
		asset_line_edit.text = "-1"
		layer_line_edit.text = "0"
		layer_offset_spin_box.set_value_no_signal(0)
		position_x_spin_box.set_value_no_signal(0)
		position_y_spin_box.set_value_no_signal(0)
		rotation_spin_box.set_value_no_signal(0)
		scale_x_spin_box.set_value_no_signal(0)
		scale_y_spin_box.set_value_no_signal(0)
		
		layer_button.disabled = true
		layer_offset_spin_box.editable = false
		position_x_spin_box.editable = false
		position_y_spin_box.editable = false
		rotation_spin_box.editable = false
		scale_x_spin_box.editable = false
		scale_y_spin_box.editable = false

func set_select(new_type, part_index, state_code, element_index):
	if AvatarDollDataMgr.initialed == false or new_type not in AvatarDollDataMgr.avatar_doll_data:
		return
	
	avatar_type_combo.set_block_signals(true)
	avatar_type_combo.selected = AvatarDollDataMgr.avatar_part_scope.keys().find(new_type)
	avatar_type_combo.set_block_signals(false)
	state_panel.avatar_type = new_type
	avatar_type = new_type
	load_data()
	
	if part_index < AvatarDollDataMgr.avatar_doll_data[avatar_type].size():
		avatar_part_combo.selected = part_index
		_current_part = AvatarDollDataMgr.avatar_doll_data[avatar_type][part_index]
	
	if state_code in _current_part["Elements"]:
		state_panel.set_state_code(state_code)
		_current_state = state_code
	
	if element_index >= 0 and element_index < _current_part["Elements"][state_code].size():
		_current_elements = _current_part["Elements"][state_code]
		_current_element_index = element_index
		_current_element = _current_elements[element_index]
		canvas_2d.load_elements(_current_elements, element_index)
	
	#update_property()

func set_palette(index):
	var state_code = state_panel.current_state_code 
	if state_code not in _current_part["Elements"]:
		_current_state = null
		return

	var palettes = AvatarDollDataMgr.get_render_palettes(avatar_type, avatar_part_combo.selected, state_code, index - 1, false)

	for asset_name in palettes:
		canvas_2d.update_palette(asset_name, palettes[asset_name])

func _on_avatar_type_combo_item_selected(index):
	avatar_type = avatar_type_combo.get_item_text(index)
	state_panel.avatar_type = avatar_type
	load_data()

func _on_avatar_part_combo_item_selected(index):
	_current_part = AvatarDollDataMgr.avatar_doll_data[avatar_type][index]
	
	update_data()
	canvas_2d.zoom_fit()

func _on_palette_combo_item_selected(index):
	set_palette(index)

func _on_state_treeview_select_change(_avatar_type, _index, _state_code):
	update_data()
	set_palette(palette_combo.selected)
	canvas_2d.zoom_fit()

func _on_canvas_mouse_entered():
	canvas_2d.update_mouse_in_canvas(true)

func _on_canvas_mouse_exited():
	canvas_2d.update_mouse_in_canvas(false)

func _on_canvas_element_selected(index: int):
	_current_element_index = index
	_current_element = _current_elements[index] if index != -1 else null
	update_property()

func _on_canvas_element_property_changed(_index: int, _position: Vector2, _rotation: float, _scale: Vector2, _skew: float):
	if _current_part == null or _current_state == null:
		return
		
	_current_element["PositionX"] = _position.x
	_current_element["PositionY"] = _position.y
	_current_element["Rotation"] = _rotation
	_current_element["ScaleX"] = _scale.x
	_current_element["ScaleY"] = _scale.y
	_current_element["Skew"] = _skew
	update_property()

func _on_canvas_element_action(index: int, action: String, data: Dictionary):
	if action == "UP" and index > 0:
		var temp = _current_elements[index - 1]
		_current_elements[index - 1] = _current_elements[index]
		_current_elements[index] = temp
		canvas_2d.load_elements(_current_elements, index - 1)
		
	elif action == "DOWN" and index < _current_elements.size() - 1:
		var temp = _current_elements[index + 1]
		_current_elements[index + 1] = _current_elements[index]
		_current_elements[index] = temp
		canvas_2d.load_elements(_current_elements, index + 1)
		
	elif action == "REMOVE":
		var msg = "确定删除 %s 吗？" % AvatarDollDataMgr.get_asset_name(_current_elements[index]["AssetId"])
		var msg_box = MessageBox.warning(self, 
			"警告", msg, 
			MessageBox.StandardButton.YES | MessageBox.StandardButton.NO)
		msg_box.accepted.connect(func(): 
			_current_elements.remove_at(index)
			canvas_2d.load_elements(_current_elements)
			state_panel.update_data()
		)
		pass
	
func _on_property_changed(value, property: String):
	_current_element[property] = value
	update_property()
	canvas_2d.update_element(_current_element_index, _current_element)

func _on_layer_button_pressed():
	var pos = layer_button.global_position + layer_button.get_rect().size
	pos.x -= popup_panel.size.x
	popup_panel.position = pos 
	popup_panel.show()

func _on_layer_selecter_pressed(index):
	popup_panel.hide()
	_current_element["Layer"] = index
	update_property()
	
func _on_files_dropped(files):
	if not AvatarDollDataMgr.initialed:
		return
	
	if mouse_over_control(sub_viewport_container):
		if _current_state:
			for file_path in files:
				var asset_id = AvatarDollDataMgr.load_asset(file_path)
				if _current_elements != null:
					var element = {}
					element["AssetId"] = asset_id
					element["LayerOffset"] = 0
					element["PositionX"] = 0.0
					element["PositionY"] = 0.0
					element["Rotation"] = 0.0
					element["ScaleX"] = 1.0
					element["ScaleY"] = 1.0
					element["Skew"] = 0.0
					
					match avatar_type:
						"Bodies": element["Layer"] = 0
						"Heads": element["Layer"] = 9
						"Hairs": element["Layer"] = 10
						"Faces": element["Layer"] = 14
						"Clothes": element["Layer"] = 7
					
					_current_elements.append(element)
			update_data()
			canvas_2d.set_selected(_current_elements.size() - 1)
		
		else:
			for file_path in files:
				var asset_id = AvatarDollDataMgr.load_asset(file_path)
			update_data()
		
	elif mouse_over_control(asset_panel):
		for file_path in files:
			var asset_id = AvatarDollDataMgr.load_asset(file_path)
		update_data()

func _on_asset_dropped(asset_name, pos):
	if _current_elements == null:
		return
		
	var element = {}
	element["AssetId"] = AvatarDollDataMgr.get_asset_id(asset_name)
	element["LayerOffset"] = 0
	element["PositionX"] = pos.x
	element["PositionY"] = pos.y
	element["Rotation"] = 0.0
	element["ScaleX"] = 1.0
	element["ScaleY"] = 1.0
	element["Skew"] = 0.0
	
	match avatar_type:
		"Bodies": element["Layer"] = 0
		"Heads": element["Layer"] = 9
		"Hairs": element["Layer"] = 10
		"Faces": element["Layer"] = 14
		"Clothes": element["Layer"] = 7
				
	_current_elements.append(element)
	update_data()
	canvas_2d.set_selected(_current_elements.size() - 1)

func _on_asset_updated():
	update_data()

func mouse_over_control(node: Control):
	var rect = node.get_global_transform() * node.get_rect()
	var mouse = get_global_mouse_position()
	return rect.has_point(mouse)
