import type { Vec3 } from "../../engine/math/Vec3"
import type { Mesh } from "../../engine/scene/Mesh"
import { oak } from "./trees/Oak"
import { spruce } from "./trees/Spruce"
import { birch } from "./trees/Birch"

export type TreeKind = "oak" | "spruce" | "birch"

/** One procedural tree instance. `growth` 0..1 runs sapling -> full grown: it scales
 *  height and girth and adds canopy blobs / tiers. `seed` drives the per-tree random
 *  wobble so a forest doesn't look cloned. */
export type Tree = {
  kind: TreeKind
  /** Trunk base, sitting on the ground. */
  position: Vec3
  growth: number
  seed: number
}

/** Definition of a tree species: which chunk materials its trunk + foliage bake
 *  into, plus how to append its geometry. Each lives in its own `trees/<Kind>.ts`
 *  module (silhouette carries the species read); this file just assembles them.
 *  `trunk`/`foliage` are chunk-material keys (see `level.ts` `ChunkMaterials`):
 *  oak/spruce use the brown `bark`, birch the white `birch`; foliage is the oak
 *  `leaf` or spruce `needle`. */
export type TreeSpecies = {
  kind: TreeKind
  trunk: string
  foliage: string
  build: (tree: Tree, trunk: Mesh, foliage: Mesh, lod: "full" | "impostor") => void
}

/** All tree species (also the placement roll's palette). Trees are baked at load,
 *  not shipped per frame, so this order isn't an id contract like `MOB_KINDS` -- but
 *  keeping it lets placement + tests stay registry-driven. */
export const TREE_KINDS: TreeKind[] = ["oak", "spruce", "birch"]

/** The per-species definitions, one module each. Imported (not cloned) wherever
 *  used, so it works the same on the main thread and in workers. */
const SPECIES: Record<TreeKind, TreeSpecies> = { oak, spruce, birch }

export namespace Tree {
  /** The species definition for a kind (its trunk/foliage materials + geometry). */
  export function species(kind: TreeKind): TreeSpecies {
    return SPECIES[kind]
  }

  /** Append one tree into the caller-provided `trunk` + `foliage` meshes (which the
   *  caller selects from the species' `trunk`/`foliage` material keys). `lod`
   *  "impostor" bakes a much cheaper stand-in for far chunks; "full" is up close. */
  export function build(tree: Tree, trunk: Mesh, foliage: Mesh, lod: "full" | "impostor" = "full"): void {
    SPECIES[tree.kind].build(tree, trunk, foliage, lod)
  }
}
