extends Node3D

# Demo_3D: renders multiple stacked levels of Brogue dungeons using GridMap.
# Chasm cells are rendered as empty (no tile), so looking down through one
# reveals the floor of the level below.

# Must match src/gen/grid.h
const T_NOTHING      := 0
const T_FLOOR        := 1
const T_WALL         := 2
const T_DOOR         := 3
const T_CORRIDOR     := 4
const T_LIQUID       := 5
const T_BRIDGE       := 6
const T_STAIRS_UP    := 7
const T_STAIRS_DOWN  := 8

const L_NONE      := 0
const L_WATER     := 1
const L_LAVA      := 2
const L_CHASM     := 3
const L_BRIMSTONE := 4

# Match the tile IDs exposed by MeshLibraryBuilder.
const TILE_FLOOR       := 0
const TILE_WALL        := 1
const TILE_DOOR        := 2
const TILE_CORRIDOR    := 3
const TILE_WATER       := 4
const TILE_LAVA        := 5
const TILE_BRIMSTONE   := 6
const TILE_BRIDGE      := 7
const TILE_STAIRS_UP   := 8
const TILE_STAIRS_DOWN := 9

@export var base_seed: int = 2321
@export var depth_start: int = 20
@export var level_count: int = 10
@export var level_spacing: float = 6.0

@onready var levels_root: Node3D = $Levels
@onready var camera: Camera3D = $FlyCamera

var _mesh_library: MeshLibrary

func _ready() -> void:
	_mesh_library = MeshLibraryBuilder.build()

	var total_chasm_cells := 0
	for level_index in range(level_count):
		var level_seed := base_seed + level_index
		var depth := depth_start + level_index
		var gen := BrogueGen.new()
		var grid: Dictionary = gen.generate(level_seed, depth)
		gen.free()

		var grid_map := GridMap.new()
		grid_map.name = "Level%d" % level_index
		grid_map.mesh_library = _mesh_library
		grid_map.cell_size = Vector3(1, 1, 1)
		grid_map.position.y = -level_index * level_spacing
		levels_root.add_child(grid_map)

		var chasm_cells := _populate_level(grid_map, grid)
		total_chasm_cells += chasm_cells

		print("Level %d: seed=%d depth=%d rooms=%d machines=%d chasms=%d"
			% [level_index, level_seed, depth,
			   (grid["rooms"] as Array).size(),
			   (grid["machines"] as Array).size(),
			   chasm_cells])

	# Position the camera above level 0's grid center, tilted down.
	var grid_w := 79
	var grid_h := 29
	camera.position = Vector3(grid_w * 0.5, 14, grid_h * 0.5 + 18)
	camera.rotation_degrees = Vector3(-35, 0, 0)

	print("Demo3D ready. %d levels, %d chasm cells total." % [level_count, total_chasm_cells])

# Populate one level's GridMap from the grid dict. Returns the count of
# chasm cells that were deliberately skipped (for reporting).
func _populate_level(grid_map: GridMap, grid: Dictionary) -> int:
	var w: int = grid["width"]
	var h: int = grid["height"]
	var terrain: PackedByteArray = grid["terrain"]
	var liquid: PackedByteArray = grid["liquid"]

	var chasm_cells := 0
	for y in range(h):
		for x in range(w):
			var idx := y * w + x
			var t: int = terrain[idx]
			var liq: int = liquid[idx]
			# Chasm liquid renders as an actual see-through pit.
			if t == T_LIQUID and liq == L_CHASM:
				chasm_cells += 1
				continue
			var tile_id := _tile_for(t, liq)
			if tile_id == -1:
				continue  # T_NOTHING or other empty — leave unrendered
			# GridMap coords: (X, Y, Z). We want dungeon x → X, dungeon y → Z.
			grid_map.set_cell_item(Vector3i(x, 0, y), tile_id)
	return chasm_cells

func _tile_for(terrain: int, liquid: int) -> int:
	match terrain:
		T_FLOOR:        return TILE_FLOOR
		T_CORRIDOR:     return TILE_CORRIDOR
		T_DOOR:         return TILE_DOOR
		T_WALL:         return TILE_WALL
		T_BRIDGE:       return TILE_BRIDGE
		T_STAIRS_UP:    return TILE_STAIRS_UP
		T_STAIRS_DOWN:  return TILE_STAIRS_DOWN
		T_LIQUID:
			match liquid:
				L_WATER:     return TILE_WATER
				L_LAVA:      return TILE_LAVA
				L_BRIMSTONE: return TILE_BRIMSTONE
				L_CHASM:     return -1  # empty cell — see through to level below
				_:           return TILE_WATER
		_: return -1  # T_NOTHING or unknown
