extends Node3D


const AUTOSAVE_FILE = "__autosave__"

@onready var level = $"SubViewportContainer/SubViewport/level"
@onready var ui = $"ui"
@onready var level_manager = $"/root/LevelManager"
@onready var selection_ui = $"ui/selection_ui"
@onready var select_box = $"tile_offset/select_box"

var editor_mode = preload("res://scenes/level_editor/editor_mode.gd").new()

var element_rotation = 0
var selected_element = "tile_flat"
var selected_class = "tile"

var current_level_name = ""

var new_select_position_world
var new_select_position_level
var new_select_layer = 0
var has_focus = false

var active_tile_material_set = "stone01"
var active_tile_material_top
var active_tile_material_wall
var active_tile_material_top_prev
var active_tile_material_wall_prev

var select_box_space_size
var select_box_pos_world = Vector3(0, 0, 0)
var select_box_pos_level = Vector3(0, 0, 0)
var select_box_mouse = false

const HISTORY_MAX_SIZE = 50
var actions_history = []


func _ready():
	self.select_box.level = self.level
	level_manager.editor = self
	level_manager.exec_context = "editor"
	self.select_box_space_size = self.level.camera_rig.camera_space_size - self.level.ELEMENT_SIZE
	self.select_element(self.level.templates.TILE_FLAT, self.level.builder.CLASS_TILE)
	
	if level_manager.selected_level == null or level_manager.selected_level == "":
		
		_load_autosave()
	else:
		if level_manager.level_exists(level_manager.selected_level):
			self.level.loader.load_level_file(level_manager.selected_level)
			self.set_level_name(level_manager.selected_level)
		else:
			level_manager.selected_level = ""
			_load_autosave()
		
	update_select_box_materials()
	self.level.builder.editor = self
	self.ui.initialize(self)

func _load_autosave():
	self.level.loader.load_level_file(self.AUTOSAVE_FILE)
	self.set_level_name("")

func _input(event):
	if event is InputEventMouseMotion:
		if event.relative.length_squared() > 0.01:
				self.select_box_mouse = true



func _process(_delta):
	new_select_position_level = self.select_box_pos_level
	new_select_layer = new_select_position_level.z
	_handle_editor_input(_delta)


func _physics_process(_delta):
	self.snap_select_box()	


func _handle_editor_input(_delta):
	if !has_focus:
		return
	
	new_select_position_world = Vector3(0, 0, 0)
	new_select_layer = new_select_position_level.z
	
	
	
	
		
	if Input.is_action_just_pressed("save"):
		autosave()
		quicksave()
		
	if Input.is_action_just_pressed("ui_cancel"):
		var success
		if self.editor_mode.current != "menu":
			success = self.editor_mode.set_current("menu")
		else:
			if self.ui.pause_menu.is_visible():
				success = self.editor_mode.return_to_previous()
			else:
				print ("it is not the pause menu that is open...")
				success = false
		if success:
			if not self.ui.pause_menu.is_visible():
				open_pause_menu()
			#returning back is managed from the pause menu, as the editor (and game) will be paused
			
	
	
	if Input.is_action_just_pressed("ed_toggle_picker"):
		var success
		if self.editor_mode.current != "menu":
			success = self.editor_mode.set_current("menu")
		else:
			if self.ui.picker.is_visible():
				success = self.editor_mode.return_to_previous()
			else:
				print ("it is not the picker that is open...")
				success = false
		if success:
			if not self.ui.picker.is_visible():
				open_picker()
			else:
				close_picker()
	if Input.is_action_just_pressed("open_user_dir"):
		OS.shell_open(ProjectSettings.globalize_path("user://"))
	
	if Input.is_action_just_pressed("ed_toggle_camera_mode"):
		var success
		if self.editor_mode.current != "level_cam":
			success = self.editor_mode.set_current("level_cam")
			if success:
				set_level_camera()
		else:
			success = self.editor_mode.return_to_previous()
			
			if success:
				set_editor_camera()
				
	if self.editor_mode.current == "edit":
		if Input.is_action_just_pressed("ed_tile_layer_raise"):
			new_select_layer += 1
		
		if Input.is_action_just_pressed("ed_tile_layer_sink"):
			new_select_layer -= 1
			
		if Input.is_action_just_pressed("ed_tile_rotate_left"):
			self.rotate_ccw()
			self.refresh_element()
		
		if Input.is_action_just_pressed("ed_tile_rotate_right"):
			self.rotate_cw()
			self.refresh_element()	
		
		if Input.is_action_pressed("ed_place_tile"):
			place_element()
			
		if Input.is_action_pressed("ed_remove_tile"):
			clear_element()
	
	
		if level.camera_rig.ray_hit:
			new_select_position_world.x = level.camera_rig.ray_hit_position.x
			new_select_position_world.z = level.camera_rig.ray_hit_position.z
		var new_position = level.local_to_level(new_select_position_world, select_box_pos_level.z)
		new_position.z = new_select_layer
		select_element_at_position(new_position)


func select_element_at_position(position):
	if self.level.is_pos_out_of_bounds(position):
		return false
	else:
		self.set_select_box_position(position)
		return true


func autosave():
	self.level.loader.save_level_file(self.AUTOSAVE_FILE)


func place_element():
	if not select_box.is_visible():
		return
	var element = self.level.get_element(self.select_box_pos_level)
	if element == null:
		return

	#self.write_action_history({
	#	"type" : "add",
	#	"class" : self.selected_class,
	#	"position" : self.map.tile_box_position,
	#	"tile" : self.selected_element,
	#	"rotation" : self.element_rotation,
	#})
	
	self._place_element(self.selected_class, self.select_box_pos_level, self.selected_element, self.element_rotation, self.active_tile_material_set)


func _place_element(element_class, element_position, element_type, _element_rotation, _element_material):
	if element_class == self.level.builder.CLASS_TILE:
		self.level.builder.place_tile(element_position, element_type, _element_rotation, _element_material)
	elif element_class == self.level.builder.CLASS_OBJECT:
		self.level.builder.place_object(element_position, element_type, _element_rotation)
	elif element_class == self.level.builder.CLASS_FLOOR_OBJECT:
		self.level.builder.place_floor_object(element_position, element_type, _element_rotation)
	else:
		print ("unknown element class to place given")


func clear_element(all_layers = false):

	if editor_mode.current != "edit":
		return
	if !all_layers:
		self.level.builder.clear_element_layer(self.select_box_pos_level, self.selected_class)
	else:
		self.level.builder.clear_element_layer(self.select_box_pos_level)


func refresh_element():
	self.select_element(self.selected_element, self.selected_class)


func select_element(element_name, type):
	self.selected_element = element_name
	self.selected_class = type
	var new_mesh = self.level.templates.get_template_mesh(element_name)
	self.select_box.set_placement_mesh(new_mesh)


func rotate_ccw():
	self.element_rotation += 90
	if self.element_rotation >= 360:
		self.element_rotation = 0
	
	self.select_box.set_placement_mesh_rotation(self.element_rotation)


func rotate_cw():
	self.element_rotation -= 90
	if self.element_rotation < 0:
		self.element_rotation = 270
	
	self.select_box.set_placement_mesh_rotation(self.element_rotation)


func handle_picker_output(args):
	var level_name = args[0]
	var context = args[1]

	if context == "save":
		self.level.loader.save_level_file(level_name)
	elif context == "load":
		self.level.loader.load_level_file(level_name)
		self.actions_history = []

	self.close_picker()
	if self.level.metadata.has("name"):
		self.set_level_name(self.level.metadata["name"])


func quicksave():
	if self.current_level_name != "":
		self.level.loader.save_level_file(self.current_level_name)
		print ("saving as: " + str(self.current_level_name))


func set_level_name(level_name):
	self.current_level_name = level_name
	self.ui.set_level_name(level_name)


func open_picker():
	print ("open picker")
	self.ui.show_picker()

	self.ui.picker.bind_cancel(self, "close_picker")
	self.ui.picker.bind_success(self, "handle_picker_output")
	self.ui.picker.set_name_mode()
	self.ui.set_level_name(self.current_level_name, true)
	self.select_box.hide()
	self.editor_mode.set_current("menu")
	self.level.camera_rig.navigation_enabled = false


func close_picker():
	self.ui.hide_picker()
	self.select_box.show()
	self.level.camera_rig.navigation_enabled = true
	self.editor_mode.set_current("edit")
	self.ui.show_level_name()
	
func open_pause_menu():
	print ("open pause menu")
	self.ui.show_pause_menu()

	#self.ui.picker.bind_cancel(self, "close_picker")
	#self.ui.picker.bind_success(self, "handle_picker_output")
	#self.ui.picker.set_name_mode()
	self.ui.set_level_name(self.current_level_name, true)
	self.select_box.hide()
	self.editor_mode.set_current("menu")
	self.level.camera_rig.navigation_enabled = false
	
func on_pause_menu_closed():

	self.select_box.show()
	self.level.camera_rig.navigation_enabled = true
	self.editor_mode.set_current("edit")
	self.ui.show_level_name()

func set_level_camera():
	self.select_box.visible = false
	self.level.camera_rig.set_active_camera("game")
	
func set_editor_camera():
	self.select_box.visible = true
	self.level.camera_rig.set_active_camera("editor")

func _on_element_select_button_pressed(element, button, element_class):
	if element_class == "tile":
		self.select_element(element, self.level.builder.CLASS_TILE)
	elif element_class == "object":
		self.select_element(element, self.level.builder.CLASS_OBJECT)
	elif element_class == "floor_object":
		self.select_element(element, self.level.builder.CLASS_FLOOR_OBJECT)
	elif element_class == "decoration":
		self.select_element(element, self.level.builder.DECORATION)
	
	if selection_ui.active_button != button:
		selection_ui.active_button.set_as_selected(false)
		selection_ui.active_button = button
		
	button.set_as_selected(true)


func _on_sub_viewport_container_mouse_entered():
	has_focus = true


func _on_sub_viewport_container_mouse_exited():
	has_focus = false


func set_select_box_position(position):
	if Input.is_action_pressed("ed_camera_rotate"):
		return
	self.select_box_pos_level = position
	self.select_box_pos_world = self.level.level_to_local(self.select_box_pos_level)
	
	self.level.camera_rig.select_box_pos_world = self.select_box_pos_world
	self.level.camera_rig.selected_layer_position = position.z  * 0.8 - 0.4


func snap_select_box():
	var box_position = self.select_box.get_position()
	var placement = self.level.level_to_local(self.select_box_pos_level)
	self.select_box.set_position(placement)


func update_active_materials():
	active_tile_material_top = level.templates.get_tile_material(active_tile_material_set, "top")
	active_tile_material_wall = level.templates.get_tile_material(active_tile_material_set, "wall")
	active_tile_material_top_prev = level.templates.get_tile_preview_material(active_tile_material_set, "top")
	active_tile_material_wall_prev = level.templates.get_tile_preview_material(active_tile_material_set, "wall")


func update_select_box_materials():
	self.select_box.set_placement_mesh_material(0, active_tile_material_top_prev)
	self.select_box.set_placement_mesh_material(1, active_tile_material_wall_prev)
	
func wipe_editor():
	
	self.set_level_name("")
	self.level.builder.wipe_level()
	self.level.wipe_metadata()
	#self.actions_history = []
