@tool
extends Node

# =============================================================================
# art_kit.gd — Modular Art Kit Factory
# =============================================================================
# Provides factory methods for spawning modular environment pieces and a
# preview catalogue for map builders.
#
# Each piece is a standalone .tscn under pieces/ with:
#   - CSG shapes (Box3D, Cylinder3D, Polygon3D, Combiner3D)
#   - Solid-color StandardMaterial3D placeholders (roughness 0.8, metallic 0.0)
#   - Collision enabled (use_collision = true or StaticBody3D + CollisionShape3D)
#   - < 200 tris each
#
# Usage:
#   var piece = ArtKit.spawn_piece("crate", parent_node)
#   var cat  = ArtKit.preview_catalogue()
#   var stack = ArtKit.random_crate_layout(3, 2)  # returns parent Node3D
# =============================================================================

const PIECES_DIR := "res://client/assets/scenes/modular/pieces/"

# Catalogue definition: name, description, filename (without .tscn)
const CATALOGUE: Array[Dictionary] = [
	{
		"name": "floor_tile",
		"description": "2×2×0.2m concrete slab — grey",
		"file": "floor_tile"
	},
	{
		"name": "wall_segment",
		"description": "4×0.2×3m wall panel — blue-grey",
		"file": "wall_segment"
	},
	{
		"name": "corner_wall",
		"description": "L-shaped corner piece (2m each leg) — blue-grey",
		"file": "corner_wall"
	},
	{
		"name": "pillar",
		"description": "0.3×3×0.3m column — dark grey",
		"file": "pillar"
	},
	{
		"name": "crate",
		"description": "1×1×1m storage box — brown/tan",
		"file": "crate"
	},
	{
		"name": "barrel",
		"description": "0.6m radius × 1m tall cylinder — red",
		"file": "barrel"
	},
	{
		"name": "cover_wall",
		"description": "2×0.2×1.3m low wall (crouch-height cover) — grey",
		"file": "cover_wall"
	},
	{
		"name": "ramp",
		"description": "2×2m, 30° incline ramp — yellow",
		"file": "ramp"
	},
	{
		"name": "stairs",
		"description": "3-step staircase (2m wide, 0.25m rise per step) — grey",
		"file": "stairs"
	},
	{
		"name": "window_frame",
		"description": "4×3m wall with 2×2m opening — blue-grey",
		"file": "window_frame"
	}
]


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------

## Spawns a piece by name, adds it as a child of `parent`, and returns it.
## Returns null if the piece name is unknown or the scene fails to load.
static func spawn_piece(piece_name: String, parent: Node) -> Node3D:
	var entry := _find_entry(piece_name)
	if entry.is_empty():
		push_error("ArtKit: Unknown piece '%s'. Use preview_catalogue() to see available pieces." % piece_name)
		return null

	var path := PIECES_DIR + entry.file + ".tscn"
	var scene := load(path)
	if scene == null:
		push_error("ArtKit: Failed to load scene at '%s'." % path)
		return null

	var instance: Node3D = scene.instantiate()
	parent.add_child(instance)
	instance.owner = parent if not Engine.is_editor_hint() else _get_editor_owner(parent)
	return instance


## Returns an array of { name, description, path } for all available pieces.
static func preview_catalogue() -> Array[Dictionary]:
	var result: Array[Dictionary] = []
	for entry in CATALOGUE:
		result.append({
			"name": entry.name,
			"description": entry.description,
			"path": PIECES_DIR + entry.file + ".tscn"
		})
	return result


## Generates a random stack of crates for quick testing layouts.
## `width`  — number of crates along X (default 3)
## `height` — number of crates stacked vertically (default 2)
## Returns a Node3D containing the crate instances.
static func random_crate_layout(width: int = 3, height: int = 2) -> Node3D:
	var root := Node3D.new()
	root.name = "CrateLayout_%dx%d" % [width, height]

	var crate_scene := load(PIECES_DIR + "crate.tscn")
	if crate_scene == null:
		push_error("ArtKit: Could not load crate scene.")
		return root

	for y in range(height):
		for x in range(width):
			# Add slight random offset for natural look (±0.05m)
			var offset_x := randf_range(-0.05, 0.05)
			var offset_z := randf_range(-0.05, 0.05)
			# Full rotation in 90° increments
			var rot_y := randi() % 4 * 90.0

			var crate: Node3D = crate_scene.instantiate()
			crate.position = Vector3(x * 1.0 + offset_x, y * 1.0 + 0.5, offset_z)
			crate.rotation_degrees = Vector3(0, rot_y, 0)
			root.add_child(crate)

	return root


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------

static func _find_entry(piece_name: String) -> Dictionary:
	for entry in CATALOGUE:
		if entry.name == piece_name:
			return entry
	return {}


## Returns the editor's top-level owner so new nodes are treated as part of the scene.
static func _get_editor_owner(node: Node) -> Node:
	var owner = node
	while owner and owner.owner:
		owner = owner.owner
	return owner
