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

const TREE_ROOT = [T.treeRootLeft, T.treeRootMiddle, T.treeRootRight]

function trees(r: number, i: number, row: Block[], previousRow: Block[]) {
  const max = row.length - 1
  const h = i - 1
  const j = i + 1
  const current = row[i]
  const above = previousRow[i]
  const aboveLeft = previousRow[h]
  const aboveRight = previousRow[j]

  if (current === T.treeCrown) {
    if (i > 0) row[h] = T.treeLeaves
    if (i < max) row[j] = T.treeLeaves

  } else if (above === T.treeCrown) {
    row[i] = T.treeLeaves
    if (i > 0) row[h] = T.treeLeaves
    if (i < max) row[j] = T.treeLeaves

  } else if (above === T.treeLeaves && aboveLeft === T.treeLeaves && aboveRight === T.treeLeaves) {
    row[i] = T.treeTrunk
    if (i > 0) row[h] = T.treeLeaves
    if (i < max) row[j] = T.treeLeaves

  } else if (above === T.treeTrunk) {
    if (current === T.air) row[i] = T.treeTrunk
    else row[i] = T.treeRoot
  } else if (above === T.treeRoot) {
    row[i] = T.soil
    if (i > 0) row[h] = T.treeRoot
    if (i < max) row[j] = T.treeRoot
  }
}

function ground(r: number, i: number, current: Block, above: Block) {
  if (above === T.air) {
    if (r < P.soilHole) return T.air
    if (current === T.soil) return T.grass
  }
  return current
}

function ground_(r: number, i: number, row: Block[], previousRow: Block[]) {
  const rootParts = [T.treeRootLeft, T.treeRootMiddle, T.treeRootRight]
  const prevBlock = previousRow[i]

  if (prevBlock === T.air) {
    if (r < P.soilHole) row[i] = T.air
    else if (row[i] === T.soil) row[i] = T.grass
  } else if (rootParts.indexOf(prevBlock) >= 0) {
    if (row[i] === T.soil) row[i] = T.grass
  }
}

function rock(r: number, i: number, current: Block, above: Block) {
  if (above === T.soil && r < P.fray) return T.soil
  return current
}

function underground(r: number, i: number, current: Block, above: Block) {
  if (above === T.stone && r < P.fray) return T.stone
  return current
}

export default function createBlockExtender(rand: NoiseFunction2D) {
  function growTrees(level: number, column: number, offset: number, row: Block[], previousRow: Block[]) {
    const r = rand(level, column + offset)
    trees(r, column, row, previousRow)
  }

  function extendBlock(level: number, column: number, offset: number, current: Block, above: Block) {
    const r = rand(level, column + offset)

    if (level < L.rock) return ground(r, column, current, above)
    if (level < L.underground) return rock(r, column, current, above)
    return underground(r, column, current, above)
  }

  function extendRow(level: number, columnOffset: number, row: Block[], previousRow: Block[]) {
    for (let column = 0; column < row.length; column++) {
      if (level < L.ground) {
        // growTrees(level, column, columnOffset, row, previousRow)
      } else {
        row[column] = extendBlock(level, column, columnOffset, row[column], previousRow[column])
      }
    }
  }

  return { extendBlock, extendRow }
}
