@tool
class_name Teleport
extends Node3D


## Type of spawn-point data
enum SpawnDataType {
	## No data provided
	NONE,

	## Name of spawn-point node provided
	NODE_NAME,

	## Vector3 of spawn-point provided
	VECTOR3,

	## Transform3D of spawn-point provided
	TRANSFORM3D
}


@export_group("Teleport")

## Target scene file
@export_file('*.tscn') var scene : String

## Spawn point data
@export var spawn_data := SpawnDataType.NONE: set = _set_spawn_data

@export_group("Display")

## Title texture
@export var title: Texture2D: set = _set_title

## Can Teleporter be used
@export var active: bool = true: set = _set_active

## Is teleport beam visible if inactive
@export var inactive_beam_visible: bool = false: set = _set_inactive_beam_visible

## The beam color in active state
@export var active_beam_color: Color = Color("#2b40f8"): set = _set_active_beam_color

## The beam color in inactive state
@export var inactive_beam_color: Color = Color("#ad0400"): set = _set_inactive_beam_color


# Spawn point node-name
var spawn_point_name := ""

# Spawn point position
var spawn_point_position := Vector3.ZERO

# Spawn point transform
var spawn_point_transform := Transform3D.IDENTITY

# Scene base
var _scene_base : XRToolsSceneBase


func _ready():
	_scene_base = XRTools.find_xr_ancestor(self, "*", "XRToolsSceneBase")
	_update_title()
	_update_teleport()


# Called when the player enters the teleport area
func _on_TeleportArea_body_entered(body: Node3D):
	# Skip if scene base is not known
	if not _scene_base:
		return

	# Skip if not the player body
	if not body.is_in_group("player_body"):
		return

	# Skip if not active
	if not active:
		return

	# Teleport
	if scene == "":
		_scene_base.exit_to_main_menu()
	elif spawn_data == SpawnDataType.NODE_NAME:
		_scene_base.load_scene(scene, spawn_point_name)
	elif spawn_data == SpawnDataType.VECTOR3:
		_scene_base.load_scene(scene, spawn_point_position)
	elif spawn_data == SpawnDataType.TRANSFORM3D:
		_scene_base.load_scene(scene, spawn_point_transform)
	else:
		_scene_base.load_scene(scene)


# Provide custom property information
func _get_property_list() -> Array[Dictionary]:
	# Return extra properties
	return [
		{
			name = "Teleport",
			type = TYPE_NIL,
			usage = PROPERTY_USAGE_GROUP
		},
		{
			name = "spawn_point_name",
			type = TYPE_STRING,
			usage = PROPERTY_USAGE_DEFAULT \
					if spawn_data == SpawnDataType.NODE_NAME \
					else PROPERTY_USAGE_NO_EDITOR
		},
		{
			name = "spawn_point_position",
			type = TYPE_VECTOR3,
			usage = PROPERTY_USAGE_DEFAULT \
					if spawn_data == SpawnDataType.VECTOR3 \
					else PROPERTY_USAGE_NO_EDITOR
		},
		{
			name = "spawn_point_transform",
			type = TYPE_TRANSFORM3D,
			usage = PROPERTY_USAGE_DEFAULT \
					if spawn_data == SpawnDataType.TRANSFORM3D \
					else PROPERTY_USAGE_NO_EDITOR
		}
	]


# Allow revert of custom properties
func _property_can_revert(property : StringName) -> bool:
	match property:
		"spawn_point_name":
			return true
		"spawn_point_position":
			return true
		"spawn_point_transform":
			return true
		_:
			return false


# Provide revert values for custom properties
func _property_get_revert(property : StringName): # Variant
	match property:
		"spawn_point_name":
			return ""
		"spawn_point_position":
			return Vector3.ZERO
		"spawn_point_transform":
			return Transform3D.IDENTITY


func set_collision_disabled(p_disable : bool) -> void:
	if Engine.is_editor_hint():
		return

	# Update processing (PROCESS_MODE_DISABLED turns off physics)
	if p_disable:
		process_mode = PROCESS_MODE_DISABLED
	else:
		process_mode = PROCESS_MODE_INHERIT


func _set_spawn_data(p_spawn_data : SpawnDataType) -> void:
	spawn_data = p_spawn_data
	notify_property_list_changed()


func _set_title(value):
	title = value
	if is_inside_tree():
		_update_title()


func _update_title():
	if title:
		var material: ShaderMaterial = $teleport/Top.get_surface_override_material(1)
		material.set_shader_parameter("Title", title)


func _set_active(value):
	active = value
	if is_inside_tree():
		_update_teleport()


func _set_active_beam_color(value):
	active_beam_color = value
	if is_inside_tree():
		_update_teleport()


func _set_inactive_beam_color(value):
	inactive_beam_color = value
	if is_inside_tree():
		_update_teleport()


func _set_inactive_beam_visible(value):
	inactive_beam_visible = value
	if is_inside_tree():
		_update_teleport()


func _update_teleport():
	if active:
		$teleport/Cylinder.get_surface_override_material(0).set_shader_parameter("beam_color", active_beam_color)
		$teleport/Cylinder.visible = true
	else:
		$teleport/Cylinder.get_surface_override_material(0).set_shader_parameter("beam_color", inactive_beam_color)
		$teleport/Cylinder.visible = inactive_beam_visible