extends Node3D
const CENTER := Vector3.ZERO
@export var threshold: float = 0.5

var generate_mesh_shader = preload("res://SurfaceNetsWorld/generate_mesh.tres")

var regenerate_mesh = true


@export var chunk_size = 16
@export var show_sample_points = false
@export var show_surface_points = false
@export var show_surface = true

var mesh: ArrayMesh

var color = Color.RED

var meshinstance = MeshInstance3D.new()
var material = ShaderMaterial.new()

var gpu_sdf

var staticBody: StaticBody3D = StaticBody3D.new()
var collisionShape3D: CollisionShape3D = CollisionShape3D.new()


func generate_chunk(pgpu_sdf) -> void:
	signals_service.regenerate_mesh_sig.connect(_on_regenerate_mesh_sig)
	signals_service.add_matter.connect(_on_player_add_matter)
	gpu_sdf = pgpu_sdf
	material.shader = generate_mesh_shader
	meshinstance.material_override = material
	add_child(meshinstance)
	
func _input(event):
	if event is InputEventKey and event.is_action_released("RegenerateMesh"):
			regenerate_mesh = true

func _process(_delta: float) -> void:
	if regenerate_mesh:
		regenerate_mesh = false
		clear()
		var array_mesh = gpu_sdf.compute_mesh(chunk_size, threshold, self.position)
		var trimesh_collision = array_mesh.create_trimesh_shape()
		collisionShape3D.set_shape(trimesh_collision)
		staticBody = StaticBody3D.new()
		staticBody.add_child(collisionShape3D)
		add_child(staticBody)
		meshinstance.mesh = array_mesh
	if show_surface_points:
		var idx = 0
		var text_id = 0
		while idx < gpu_sdf.iout_surface_points.size()/ 2:
			text_id += 1
			var value = Vector3(gpu_sdf.iout_surface_points.get(idx), gpu_sdf.iout_surface_points.get(idx+1), gpu_sdf.iout_surface_points.get(idx+2)) - Vector3(chunk_size / 2, chunk_size / 2, chunk_size / 2)
			if gpu_sdf.iout_surface_points.get(idx) != -1.0:
				DebugDraw3D.draw_square(value, 0.2, color.from_rgba8(255, 128, 128, 255))
				if text_id % 1 == 0:
					DebugDraw3D.draw_text(value, str(value), 35)
				idx += 3
			else:
				idx += 1
	

func clear():
	if staticBody.get_children().has(collisionShape3D):
		staticBody.remove_child(collisionShape3D)
	mesh = ArrayMesh.new()


func get_index_from_coords(coords: Vector3i):
	return coords.x + coords.y * chunk_size + coords.z * chunk_size * chunk_size

var chunks_to_regenerate = [
	Vector3i(0,0,0),
	Vector3i(0,1,0),
	Vector3i(0,0,1),
	Vector3i(0,1,1),
	Vector3i(0,-1,0),
	Vector3i(0,0,-1),
	Vector3i(0,-1,-1),
	Vector3i(0,-1,1),
	Vector3i(0,1,-1),
	
	Vector3i(1,0,0),
	Vector3i(1,0,1),
	Vector3i(-1,0,0),
	Vector3i(-1,0,-1),
	Vector3i(-1,0,1),
	Vector3i(1,0,-1),
	
	Vector3i(1,1,0),
	Vector3i(-1,-1,0),
	Vector3i(-1,1,0),
	Vector3i(1,-1,0),
	Vector3i(1,1,1),
	Vector3i(-1,-1,-1),
]

func _on_regenerate_mesh_sig(pposition: Vector3i):
	if Vector3i(self.global_position) == pposition:
		regenerate_mesh = true

func _on_player_add_matter(pposition: Vector3, size: float) -> void:
	var intpposition = Vector3i(pposition.x - int(pposition.x) % chunk_size, pposition.y - int(pposition.y) % chunk_size, pposition.z - int(pposition.z) % chunk_size)
	var intposition = Vector3i(self.global_position)
	if intpposition.x == intposition.x && intpposition.y == intposition.y && intpposition.z == intposition.z:
		for chunk_pos_to_regenerate in chunks_to_regenerate:
			chunk_pos_to_regenerate = Vector3i(intpposition.x + chunk_pos_to_regenerate.x * chunk_size, intpposition.y + chunk_pos_to_regenerate.y * chunk_size, intpposition.z + chunk_pos_to_regenerate.z * chunk_size)
			signals_service.regenerate_mesh_sig.emit(chunk_pos_to_regenerate)
				
		
