-- This function is used for structures because it will update the lighting when placed.
PyuTest.register_structure = function(name, schematic, def)
  local id = core.get_current_modname() .. ":structure_block_" .. name
  core.register_node(id, {
    description = string.format("Structure Block (%s)", name),
    groups = {
      not_in_creative_inventory = 1
    },
    drawtype = "airlike",
    walkable = false,
    pointable = false,
  })

  core.register_decoration({
    sidelen = 80,
    decoration = id,
    deco_type = "simple",
    place_on = def.place_on,
    spawn_by = def.spawn_by,
    num_spawn_by = def.num_spawn_by,
    fill_ratio = def.fill_ratio,
    noise_params = def.noise_params,
    flags = def.flags or "place_center_x, place_center_y, force_placement",
    biomes = def.biomes,
    y_max = def.y_max,
    y_min = def.y_min
  })

  core.register_lbm({
    name = core.get_current_modname() .. ":spawn_" .. name,
    run_at_every_load = true,
    nodenames = { id },
    action = function(pos, node)
      core.remove_node(pos)
      core.place_schematic(pos, PyuTest.get_schematic_path(schematic), def.rotation or "random",
        def.replacements or {}, def.force_placement or true, def.flags or "place_center_x, place_center_z")
    end
  })
end

PyuTest.is_flat = function()
  return core.get_mapgen_setting("mg_name") == "flat"
end

PyuTest.SPECIAL_STONE_NOISE_PARAMS = {
  offset = 0,
  scale = 1,
  spread = { x = 250, y = 250, z = 250 },
  seed = 1536,
  octaves = 3,
  persist = 0.4,
  lacunarity = 2,
  flags = "defaults"
}

PyuTest.MOUNTAIN_STRIP_NOISE_PARAMS = {
  offset = 0,
  scale = 1,
  spread = { x = 512, y = 512, z = 512 },
  -- seed = 8425,
  octaves = 6,
  persist = 0.4,
  lacunarity = 2,
  flags = "defaults"
}

PyuTest.OVERWORLD_BIOME_TOPS = {
  lowland = 10,
  normal = 200,
  highlands = 1000,
  skyland = 31000,
}

-- Overworld biome types
PyuTest.BIOME_TYPES = {
  -- Normal biomes (Forests for example)
  NORMAL = 1,

  -- Chilly biomes, but not snowy (Taigas for example)
  CHILLY = 2,

  -- Snowy biomes (Frozen Plains for example)
  COLD = 3,

  -- Warm biomes (Savannas for example)
  WARM = 4,

  -- Hot biomes (Deserts for example)
  HOT = 5,

  -- Wasteland biomes (Wastelands and Volcano for example)
  WASTELAND = 6,

  -- Wetland biomes (Swamps for example)
  WETLAND = 7,

  -- Ocean biomes (What example do you want?)
  OCEAN = 8,

  -- Cave biomes (What example do you want?)
  CAVE = 9,

  -- Beach biomes (What example do you want?)
  BEACH = 10,
}

PyuTest.get_biomes_from_type = function(type)
  local biomes = {}

  for k, v in pairs(core.registered_biomes) do
    if v._pyutest_biome_type == type then
      biomes[k] = v
    end
  end

  return biomes
end

PyuTest.get_flowering_biomes = function()
  local biomes = {}

  for k, v in pairs(core.registered_biomes) do
    if v._pyutest_biome_flowering == true and v._pyutest_biome_flowering_extra == false then
      table.insert(biomes, k)
    end
  end

  return biomes
end

PyuTest.get_extra_flowering_biomes = function()
  local biomes = {}

  for k, v in pairs(core.registered_biomes) do
    if v._pyutest_biome_flowering == true and v._pyutest_biome_flowering_extra == true then
      table.insert(biomes, k)
    end
  end

  return biomes
end

-- wrapper around minetest.register_biome but with defaults, caves and oceans
PyuTest.register_overworld_biome = function(name, type, opts, only_base)
  local nopts = PyuTest.util.tablecopy(opts) or {}
  nopts["name"] = name
  nopts["depth_top"] = nopts["depth_top"] or 1
  nopts["depth_filler"] = nopts["depth_filler"] or 3
  nopts["depth_riverbed"] = nopts["depth_riverbed"] or 2
  nopts["depth_water_top"] = nopts["depth_water_top"] or nil -- cant think of a sane default..

  nopts["node_water"] = nopts["node_water"] or "pyutest_blocks:water_source"
  nopts["node_river_water"] = nopts["node_river_water"] or "pyutest_blocks:river_water_source"
  nopts["node_riverbed"] = nopts["node_riverbed"] or "pyutest_blocks:sand_block"
  nopts["node_sand"] = nopts["node_sand"] or "pyutest_blocks:sand_block"
  nopts["node_sandstone"] = nopts["node_sandstone"] or "pyutest_blocks:sandstone_block"

  nopts["_pyutest_biome_flowering"] = nopts["_pyutest_biome_flowering"] or false
  nopts["_pyutest_biome_flowering_extra"] = nopts["_pyutest_biome_flowering_extra"] or false

  if nopts["_enable_beaches"] == nil then
    nopts["_enable_beaches"] = true
  end

  local y_min = (nopts["_enable_beaches"] and not only_base) and nopts["y_min"] + 2 or nopts["y_min"]

  core.register_biome(PyuTest.util.tableconcat(nopts, {
    _pyutest_biome_type = type,
    y_min = y_min
  }))

  if only_base then
    return
  end

  if nopts["_enable_beaches"] then
    core.register_biome(PyuTest.util.tableconcat(nopts, {
      name = name .. "_beach",
      y_max = y_min,
      y_min = PyuTest.OVERWORLD_SURFACE_BOTTOM,
      node_top = nopts["node_sand"],
      depth_top = 1,
      node_filler = nopts["node_sandstone"],
      depth_filler = 1,

      heat_point = nopts["heat_point"],
      humidity_point = nopts["humidity_point"],

      _pyutest_biome_type = PyuTest.BIOME_TYPES.BEACH,
    }))
  end

  core.register_biome(PyuTest.util.tableconcat({
    name = name .. "_ocean",
    node_top = nopts["node_riverbed"],
    depth_top = 2,
    node_filler = nopts["node_riverbed"],
    depth_filler = 3,
    depth_riverbed = 2,

    node_water = nopts["node_water"],
    node_river_water = nopts["node_river_water"],

    heat_point = nopts["heat_point"],
    humidity_point = nopts["humidity_point"],

    y_max = 0,
    y_min = PyuTest.OVERWORLD_OCEAN_MIN
  }, {
    _pyutest_biome_type = PyuTest.BIOME_TYPES.OCEAN,
    _pyutest_ocean_type = type
  }))

  core.register_biome(PyuTest.util.tableconcat({
    name = name .. "_deep_ocean",

    node_top = nopts["node_riverbed"],
    depth_top = 2,
    node_filler = nopts["node_riverbed"],
    depth_filler = 3,
    depth_riverbed = 2,

    node_water = nopts["node_water"],
    node_river_water = nopts["node_river_water"],

    heat_point = nopts["heat_point"],
    humidity_point = nopts["humidity_point"],

    y_max = PyuTest.OVERWORLD_DEEP_OCEAN_MAX,
    y_min = PyuTest.OVERWORLD_DEEP_OCEAN_MIN,
    vertical_blend = 5
  }, {
    _pyutest_biome_type = PyuTest.BIOME_TYPES.OCEAN,
    _pyutest_ocean_type = type
  }))

  core.register_biome(PyuTest.util.tableconcat({
    name = name .. "_cave",
    heat_point = nopts["heat_point"],
    humidity_point = nopts["humidity_point"],
    y_max = PyuTest.CAVE_TOP,
    y_min = PyuTest.CAVE_BOTTOM,
  }, {
    _pyutest_biome_type = PyuTest.BIOME_TYPES.CAVE,
    _pyutest_cave_type = type
  }))

  core.register_biome(PyuTest.util.tableconcat({
    name = name .. "_deep_cave",
    heat_point = nopts["heat_point"],
    humidity_point = nopts["humidity_point"],
    y_max = PyuTest.CAVE_BOTTOM,
    y_min = PyuTest.OVERWORLD_BOTTOM,
    node_stone = "pyutest_blocks:darkstone_block"
  }, {
    _pyutest_biome_type = PyuTest.BIOME_TYPES.CAVE,
    _pyutest_cave_type = type
  }))
end
