import type { NoiseFunction2D } from 'simplex-noise'
import {blockTypes as T, level as L, probability as P, type Block} from './def'

export default function createBlockGenerator(rand: NoiseFunction2D) {
  // randomly generate a block
  // level: number, smaller is "higher"
  // column: number, the x-axis
  // before: Block, the block type left of (before) this block
  // above: Block, the block type above this block
  const generateBlock = (level: number, column: number, before: Block, above: Block): Block => {
    // no randomness needed, there is always air above the trees
    if (level < L.treeTop) return T.air

    const r = rand(level, column)

    // Air layer: mostly air, sometimes trees
    if (level < L.ground) {
      if (level === L.treeTop && r < P.tree) return T.treeTopMiddle
      return T.air
    }

    // Soil layer: Mostly soil, sometimes gravel
    if (level < L.rock) {
      if (r < P.soilGravel) return T.soilGravel
      else return T.soil
    }

    // Rock level: Mostly stone, sometimes gravel
    if (level < L.underground) {
      if (r < P.stoneGravel) return T.stoneGravel
      else return T.stone
    }

    // Underground: Mostly bedrock, sometimes caves
    // the probability for a cave rises with the level
    const a = P.cave / L.caveMax**2
    const p = Math.min(P.cave, a * level**2)

    if (r < p) return T.cave
    return T.bedrock
  }

  const fillRow = (level: number, column: number, row: Block[], previousRow: Block[]) => {
    for (let i = 0; i < row.length; i++) {
      row[i] = generateBlock(level, column + i, row[i - 1], previousRow[i])
    }
  }

  return fillRow
}
