-- 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 = {
	extreme_lowland = 3,
	lowland = 10,
	normal = 45,
	elevated = 200,
	highlands = 1000,
	skyland = 31000,
}

PyuTest.BIOME_WEIGHTS = {
	tiny = 0.4,
	small = 0.8,
	normal = 1.0,
	big = 1.3,
	large = 1.8,
	vast = 2.2
}

-- 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:gravel_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"]
	if nopts["_enable_beaches"] and not only_base then
		y_min = nopts["y_min"] + 1
	else
		y_min = opts["y_min"]
	end

	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 - 3,
			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_ambient = "pyutest_underwater"
	}, {
		_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.OVERWORLD_BOTTOM,
		_pyutest_biome_type = PyuTest.BIOME_TYPES.CAVE,
		_pyutest_cave_type = type
	}, nopts["_pyutest_cave_opts"] or {}))
end

PyuTest.generate_pasture_schematic = function(size, node, param2)
	local schem = {
		size = { x = size, y = 2, z = size },
		data = {},
	}

	for _ = 1, size do
		for _ = 1, size do
			table.insert(schem.data, {name = node, prob = 256 / 3, param2 = param2})
			table.insert(schem.data, {name = node, prob = 256 / 3, param2 = param2})
		end
	end

	return schem
end

PyuTest.generate_boulder_schematic = function (size, node)
	local schem = {
		size = {x = size, y = size, z = size},
		data = {},
	}

	for _ = 1, size do
		for _ = 1, size do
			for _ = 1, size do
				table.insert(schem.data, {name = node, prob = 256 / 1.2})
			end
		end
	end

	return schem
end
