extends Node3D
class_name PlaceableBehaviour

@export var mesh_instances: Array[MeshInstance3D] = []
@export var collision_objects: Array[CollisionObject3D] = []
@onready var preview_material_valid: Material = preload("res://mechanics/environment/placeable/preview_valid_material.tres")
@onready var preview_material_invalid: Material = preload("res://mechanics/environment/placeable/preview_invalid_material.tres")

var original_collision_layers: Array[int]
var original_collision_masks: Array[int]
var preview_mode: bool = false
## Can be set from outside, used to tell this object if in preview mode and the current placement is invalid (e.g. on a wall)
var additional_factor_valid: bool = true
var valid_placement: bool = false:
	set(value):
		if valid_placement != value:
			valid_placement = value
			if preview_mode:
				update_preview_material()
## During placement mode, how many other objects are currently overlapping with this one
var overlapping_count: int = 0

var initialized: bool = false

func _ready():
	_init_stuff()
	
func _init_stuff():
	original_collision_layers.resize(len(collision_objects))
	original_collision_masks.resize(len(collision_objects))
	for i in range(0, len(collision_objects)):
		original_collision_layers[i] = collision_objects[i].collision_layer
		original_collision_masks[i] = collision_objects[i].collision_mask
	initialized = true

## Activates or deactivates to collisions of child objects in the 6 (PlacementCollision) layer,
## is used so that objects cannot be placed inside each other
func set_placement_collision(state: bool) -> void:
	for child in get_children():
		if child is StaticBody3D:
			# child is placementCollision hopefully
			if child.name.to_lower().contains("placement"):
				child.set_collision_layer_value(6, state)

func activate_preview():
	if not initialized:
		_init_stuff()
	
	print("activating preview")
	preview_mode = true
	recalculate_valid()
	update_preview_material()
	
	for i in range(0, len(collision_objects)):
		collision_objects[i].collision_layer = 0
		collision_objects[i].collision_mask = 0
	print("done activating")
	set_placement_collision(false)
	
func recalculate_valid():
	var valid: bool = overlapping_count <= 0
	if not additional_factor_valid:
		valid = false
	
	valid_placement = valid

func update_preview_material():
	for mesh_instance: MeshInstance3D in mesh_instances:
		var material: Material = null
		if preview_mode:
			if valid_placement:
				material = preview_material_valid
			else:
				material = preview_material_invalid
		mesh_instance.material_override = material

func deactivate_preview():
	print("deactivating preview")
	preview_mode = false
	for mesh_instance: MeshInstance3D in mesh_instances:
		mesh_instance.material_override = null
	
	for i in range(0, len(collision_objects)):
		collision_objects[i].collision_layer = original_collision_layers[i]
		collision_objects[i].collision_mask = original_collision_masks[i]
	set_placement_collision(true)

func _on_overlap_checker_body_entered(_body):
	overlapping_count += 1
	recalculate_valid()

func _on_overlap_checker_body_exited(_body):
	overlapping_count -= 1
	if overlapping_count <= 0:
		recalculate_valid()
