extends RefCounted

## Prototype QA: two short bumps on StaticBody3D siblings of Floor (same NavigationRegion3D parent).
## Avoids one body with floor + cylinder (compound internal edges caused idle jitter beside bumps).
## Bump mesh group and collision fudge: random_floor_bump_collision_constants.gd.
## Spawner called from main.gd before nav bake.
## Collision radius > mesh radius; spawn before `NavigationRegion3D.bake_navigation_mesh()`.

const BUMP_COLLISION_CONSTS_SCRIPT: Script = preload(
	"res://scripts/random_floor_bump_collision_constants.gd"
)

const COUNT: int = 2
const HEIGHT_MIN: float = 0.08
const HEIGHT_MAX: float = 0.14
const RADIUS_MIN: float = 0.36
const RADIUS_MAX: float = 0.62
const FLOOR_SINK: float = 0.008
const XZ_RANGE: float = 8.15
const MIN_PAIR_SEPARATION: float = 2.85
const MAX_PLACE_ATTEMPTS: int = 64
const EXCLUSION_MARGIN: float = 0.72


static func spawn_short_random_bumps(floor_node: StaticBody3D) -> void:
	var rng := RandomNumberGenerator.new()
	rng.randomize()
	var mat := StandardMaterial3D.new()
	mat.albedo_color = Color(0.22, 0.52, 0.32, 1.0)
	mat.roughness = 1.0
	mat.metallic = 0.0
	mat.specular_mode = 2

	var placed_xz: Array[Vector2] = []
	for idx: int in COUNT:
		var xz: Vector2 = Vector2.ZERO
		var ok := false
		for _a: int in MAX_PLACE_ATTEMPTS:
			xz = Vector2(rng.randf_range(-XZ_RANGE, XZ_RANGE), rng.randf_range(-XZ_RANGE, XZ_RANGE))
			if _xz_in_exclusion(xz):
				continue
			var far_enough := true
			for p: Vector2 in placed_xz:
				if xz.distance_to(p) < MIN_PAIR_SEPARATION:
					far_enough = false
					break
			if not far_enough:
				continue
			ok = true
			break
		if not ok:
			push_warning(
				(
					"RandomFloorBumps: could not place bump %d after %d tries"
					% [idx, MAX_PLACE_ATTEMPTS]
				)
			)
			continue
		placed_xz.append(xz)
		var h: float = rng.randf_range(HEIGHT_MIN, HEIGHT_MAX)
		var r: float = rng.randf_range(RADIUS_MIN, RADIUS_MAX)
		_add_cylinder_bump(floor_node, xz.x, xz.y, h, r, mat, idx)


static func _xz_in_exclusion(xz: Vector2) -> bool:
	var ex: Array[Vector2] = [
		Vector2(-5.0, -5.0),
		Vector2(0.0, 0.0),
		Vector2(6.0, 5.0),
		Vector2(7.5, -6.5),
		Vector2(9.0, 9.0),
	]
	var rad: Array[float] = [2.65, 1.2, 2.25, 1.65, 1.85]
	for i: int in ex.size():
		if xz.distance_to(ex[i]) < rad[i] + EXCLUSION_MARGIN:
			return true
	return false


static func _add_cylinder_bump(
	floor_node: StaticBody3D,
	x: float,
	z: float,
	height: float,
	radius: float,
	mat: StandardMaterial3D,
	idx: int
) -> void:
	var cy: float = height * 0.5 - FLOOR_SINK
	var local_center := Vector3(x, cy, z)
	var nav_parent := floor_node.get_parent()
	if nav_parent == null:
		push_error("RandomFloorBumps: Floor has no parent; cannot spawn bump")
		return

	var bump_root := StaticBody3D.new()
	bump_root.name = "RandomTestBump%d" % idx
	bump_root.add_to_group("walkable")
	bump_root.collision_layer = floor_node.collision_layer
	bump_root.collision_mask = floor_node.collision_mask
	nav_parent.add_child(bump_root)
	bump_root.global_position = floor_node.to_global(local_center)

	var mesh_inst := MeshInstance3D.new()
	mesh_inst.name = "RandomTestBump%d_mesh" % idx
	mesh_inst.add_to_group(BUMP_COLLISION_CONSTS_SCRIPT.RANDOM_FLOOR_BUMP_MESH_GROUP)
	var cm := CylinderMesh.new()
	cm.height = height
	cm.top_radius = radius
	cm.bottom_radius = radius
	cm.radial_segments = 24
	mesh_inst.mesh = cm
	mesh_inst.set_surface_override_material(0, mat)
	mesh_inst.position = Vector3.ZERO
	bump_root.add_child(mesh_inst)

	var col := CollisionShape3D.new()
	col.name = "RandomTestBump%d_shape" % idx
	var csh := CylinderShape3D.new()
	csh.height = height
	csh.radius = minf(
		radius + BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_EXTRA,
		BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_MAX
	)
	col.shape = csh
	col.position = Vector3.ZERO
	bump_root.add_child(col)
