import { BEACH, ICECAP, LIGHT_FOREST, MOUNTAIN, WATER } from "./data";
import { IslandGrid } from "./grid";

export type IsDone = boolean;
export type LobeGenerator = () => IsDone;
export type LobeGeneratorConstructor = (
  islands: IslandGrid,
  basePos: number
) => LobeGenerator;

/** form mountain with icecap */
export const BIG_MOUNTAIN: LobeGeneratorConstructor =
  (islands: IslandGrid, basePos: number) => () => {
    const mountainTiles = islands.floodSearch(
      basePos,
      (tile) => tile > MOUNTAIN
    );
    islands.dropWithin(mountainTiles);

    return mountainTiles.some((pos) => islands.data[pos] == ICECAP);
  };

/** form low-lying beach */
export const SMALL_BEACH: LobeGeneratorConstructor =
  (islands: IslandGrid, basePos: number) => () => {
    const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);

    const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
    islands.dropWithin(shoreTiles);

    return true;
  };

/** form low-lying beach that meets another island */
export const BIG_BEACH: LobeGeneratorConstructor = (
  islands: IslandGrid,
  basePos: number
) => {
  let dropped = 0;
  return () => {
    const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);

    const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
    islands.dropWithin(shoreTiles);
    dropped++;

    const landTiles = islandTiles.filter((pos) => islands.data[pos] > WATER);
    return landTiles.length > dropped;
  };
};

/** form forested zone */
export const FOREST_LOBE: LobeGeneratorConstructor =
  (islands: IslandGrid, basePos: number) => () => {
    const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);

    // grow shore
    const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
    islands.dropWithin(shoreTiles);

    // seed beach
    const beachTiles = islandTiles.filter((pos) => islands.data[pos] == BEACH);
    islands.dropWithin(beachTiles);

    // expand forest
    const forestLobe = islands.floodSearch(basePos, (tile) => tile > BEACH);
    const forestTiles = forestLobe.filter(
      (pos) => islands.data[pos] == LIGHT_FOREST
    );
    islands.dropWithin(forestTiles);
    islands.dropWithin(forestTiles);
    islands.dropWithin(forestTiles);

    return true;
  };

/** form low-lying beach with eroded sections */
export const ERODED_LOBE: LobeGeneratorConstructor =
  (islands: IslandGrid, basePos: number) => () => {
    const islandTiles = islands.floodSearch(basePos, (tile) => tile > WATER);

    const shoreTiles = islandTiles.filter((pos) => islands.data[pos] == WATER);
    islands.dropWithin(shoreTiles);

    // erode
    if (islandTiles.length > 1) {
      const erodePos = islandTiles[islands.rng() % islandTiles.length];
      islands.data[erodePos] = Math.max(islands.data[erodePos] - 1, WATER);
    }

    return true;
  };

/** form low-lying beach with eroded sections */
export const NO_ISLAND: LobeGeneratorConstructor =
  (islands: IslandGrid, basePos: number) => () => {
    return true;
  };

export const BIG_ISLANDS = [BIG_MOUNTAIN, BIG_BEACH];
export const ALL_ISLANDS = [
  BIG_MOUNTAIN,
  SMALL_BEACH,
  BIG_BEACH,
  FOREST_LOBE,
  ERODED_LOBE,
];