local internal_api = ...

local mod_name = internal_api.mod_name
local S = internal_api.translate_single

-- A Player only pressure plate
mcl_pressureplates.register_pressure_plate("mcla_codihacks:pressure_plate_copper", {
	description = S("Copper Pressure Plate"),
	texture = "mcl_copper_block.png",
	recipeitem = "mcl_copper:copper_ingot",
	sounds = mcl_sounds.node_sound_metal_defaults(),
	groups = {pickaxey = 1},
	activated_by = {player = true},
	longdesc = S(
		"A copper pressure plate is a redstone component which supplies its surrounding blocks with redstone power while a player stands on top of it. It is not triggered by anything else."),
})

-- Burning books sounds like a safe thing for society!
core.register_craft({type = "fuel", recipe = "group:book", burntime = 15})

core.register_craft({type = "fuel", recipe = "mcl_enchanting:book_enchanted", burntime = 25})

core.register_craft({
	type = "fuel",
	recipe = "mcl_fishing:fishing_rod_enchanted",
	burntime = 25,
})
core.register_craft({type = "fuel", recipe = "mcl_bows:bow_enchanted", burntime = 25})

-- Leather from saddle
core.register_craft({output = "mcl_mobitems:leather 2", recipe = {{"mcl_mobitems:saddle"}}})

-- get blocks back from stairs
core.register_craft({
	type = "cooking",
	output = "mcl_core:ironblock 2",
	recipe = "mcl_stairs:stair_ironblock",
	cooktime = 10,
})

-- get blocks back from stairs
core.register_craft({
	type = "cooking",
	output = "mcl_core:goldblock 2",
	recipe = "mcl_stairs:stair_goldblock",
	cooktime = 10,
})

-- Stack saddles and horse armour, moore loot from smelting saddles
core.override_item("mcl_mobitems:saddle", {stack_max = 16})
core.override_item("mcl_mobitems:iron_horse_armor",
                   {stack_max = 16, _mcl_cooking_output = "mcl_core:iron_ingot 3"})
core.override_item("mcl_mobitems:gold_horse_armor",
                   {stack_max = 16, _mcl_cooking_output = "mcl_core:gold_ingot 3"})
core.override_item("mcl_mobitems:diamond_horse_armor",
                   {stack_max = 16, _mcl_cooking_output = "mcl_core:diamond 3"})

-- Stackable potions, etc
for id, def in pairs(core.registered_craftitems) do
	if (def.groups.brewitem or def.groups.clock or def.groups.compass) and def.stack_max == 1 then
		core.override_item(def.name, {stack_max = 16})
	end
end

-- Compostable fish
core.override_item("mcl_fishing:fish_raw", {
	groups = {food = 2, eatable = 2, smoker_cookable = 1, compostability = 65},
})

core.override_item("mcl_fishing:fish_cooked", {
	description = S("Cooked Fish"),
	groups = {food = 2, eatable = 5, compostability = 85},
})

core.override_item("mcl_fishing:salmon_raw", {
	groups = {food = 2, eatable = 2, smoker_cookable = 1, compostability = 65},
})

core.override_item("mcl_fishing:salmon_cooked",
                   {groups = {food = 2, eatable = 6, compostability = 85}})

core.override_item("mcl_fishing:clownfish_raw",
                   {groups = {food = 2, eatable = 1, compostability = 65}})

core.override_item("mcl_fishing:pufferfish_raw",
                   {groups = {food = 2, eatable = 1, brewitem = 1, compostability = 65}})

-- More emeralds
local stonelike = {
	"mcl_core:stone",
	"mcl_core:diorite",
	"mcl_core:andesite",
	"mcl_core:granite",
	"mcl_deepslate:deepslate",
	"mcl_deepslate:tuff",
}

core.register_ore({
	ore_type = "scatter",
	ore = "mcl_core:stone_with_emerald",
	wherein = stonelike,
	clust_scarcity = 16384,
	clust_num_ores = 4,
	clust_size = 3,
	y_min = mcl_worlds.layer_to_y(-16),
	y_max = mcl_worlds.layer_to_y(320),
	biomes = {
		"ExtremeHills",
		"ExtremeHills_beach",
		"ExtremeHills_ocean",
		"ExtremeHills_deep_ocean",
		"ExtremeHills_underground",
		"ExtremeHills+",
		"ExtremeHills+_ocean",
		"ExtremeHills+_deep_ocean",
		"ExtremeHills+_underground",
		"ExtremeHillsM",
		"ExtremeHillsM_ocean",
		"ExtremeHillsM_deep_ocean",
		"ExtremeHillsM_underground",
	},
})

if world_settings.get(mod_name, "golems_eat_creepers") then
	local def = core.registered_entities["mobs_mc:iron_golem"]
	if def then def.should_attack = mcl_mobs.mob_class.should_attack end
end

if world_settings.get(mod_name, "more_lapis") then
	-- https://minecraft.wiki/w/Lapis_Lazuli_Ore#Natural_generation
	-- Add Missing -64..64 lapis check
	-- Add Missing -1..-32 lapis check
	for i = 1, 10 do

		local clust_size = 2

		if i > 6 then
			clust_size = 4
		elseif i > 3 then
			clust_size = 3
		elseif i == 1 then
			clust_size = 1
		end

		core.register_ore({
			ore_type = "scatter",
			ore = "mcl_core:stone_with_lapis",
			wherein = stonelike,
			clust_scarcity = 80000, -- BUGBUG is this rare enough?
			clust_num_ores = i,
			clust_size = clust_size,
			y_min = mcl_worlds.layer_to_y(-64),
			y_max = mcl_worlds.layer_to_y(64),
		})

		local clust_scarcity = 25000 -- BUGBUG is this rare enough?

		for j = -1, -31, -2 do
			core.register_ore({
				ore_type = "scatter",
				ore = "mcl_core:stone_with_lapis",
				wherein = stonelike,
				clust_scarcity = clust_scarcity,
				clust_num_ores = i,
				clust_size = clust_size,
				y_min = mcl_worlds.layer_to_y(j),
				y_max = mcl_worlds.layer_to_y(j - 1),
			})

			-- Rarer as we move away from 0
			clust_scarcity = clust_scarcity + 2000
		end
	end
end

-- Pink dye from cherry blossoms
core.register_craft({
	type = "shapeless",
	output = "mcl_dyes:pink",
	recipe = {"mcl_cherry_blossom:pink_petals"},
})

-- Allow budding amethysts
if world_settings.get(mod_name, "craft_buds") then
	core.register_craft({
		output = "mcl_amethyst:budding_amethyst_block",
		recipe = {
			{"", "mcl_amethyst:amethyst_shard", ""},
			{
				"mcl_amethyst:amethyst_shard",
				"mcl_amethyst:amethyst_block",
				"mcl_amethyst:amethyst_shard",
			},
			{"", "mcl_amethyst:amethyst_shard", ""},
		},
	})
end

core.register_craft({
	output = "mcl_wool:white",
	recipe = {
		{"mcl_mobitems:string", "mcl_mobitems:string"},
		{"mcl_mobitems:string", "mcl_mobitems:string"},
	},
})

core.register_chatcommand("place_all_things", {
	description = S("Place all village schematics in a grid in front of the player"),
	privs = {server = true},
	func = function(name, param)
		local pos = core.get_player_by_name(name):get_pos()

		local x = 10
		local z = 10

		for _, schem in pairs(mcl_villages.schematic_houses) do
			local placement_pos = vector.offset(pos, x, 0, z)
			local schematic = loadstring(schem.schem_lua)()

			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + 15
		end

		x = 10
		z = z + 15

		for _, schem in pairs(mcl_villages.schematic_jobs) do
			local placement_pos = vector.offset(pos, x, 0, z)
			local schematic = loadstring(schem.schem_lua)()

			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + 15
		end

		x = 10
		z = z + 15

		for _, schem in pairs(mcl_villages.schematic_lamps) do
			local placement_pos = vector.offset(pos, x, 0, z)
			local schematic = loadstring(schem.schem_lua)()

			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + 15
		end

		for _, schem in pairs(mcl_villages.schematic_bells) do
			local placement_pos = vector.offset(pos, x, 0, z)
			local schematic = loadstring(schem.schem_lua)()

			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + 15
		end

		for _, schem in pairs(mcl_villages.schematic_wells) do
			local placement_pos = vector.offset(pos, x, 0, z)
			local schematic = loadstring(schem.schem_lua)()

			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + 15
		end
	end,
})

local reverse_map = {
	desert = "Desert",
	bamboo = "BambooJungle",
	jungle = "Jungle",
	acacia = "Savanna",
	hardened_clay = "Mesa",
	mangrove = "MangroveSwamp",
	dark_oak = "RoofedForest",
	birch = "BirchForest",
	spruce = "Taiga",
	cherry = "CherryGrove",
}

core.register_chatcommand("biome_test_building", {
	description = S(
		"Places a building once for each registered biome and replaces material for that biomes"),
	privs = {maphack = true},
	params = S("<building name>"),
	func = function(name, param)
		local player = core.get_player_by_name(name)
		if param == "" then return true, S("You need to supply the name of the building") end
		local pos = vector.round(player:get_pos())

		local offset

		local x = 10
		local z = 10

		local schema

		for _, schem in pairs(mcl_villages.schematic_houses) do
			if schem.name == param then
				schema = schem
				break
			end
		end

		if not schema then
			for _, schem in pairs(mcl_villages.schematic_jobs) do
				if schem.name == param then
					schema = schem
					break
				end
			end
		end

		if not schema then
			for _, schem in pairs(mcl_villages.schematic_lamps) do
				if schem.name == param then
					schema = schem
					break
				end
			end
		end

		if not schema then
			for _, schem in pairs(mcl_villages.schematic_bells) do
				if schem.name == param then
					schema = schem
					break
				end
			end
		end

		if not schema then
			for _, schem in pairs(mcl_villages.schematic_wells) do
				if schem.name == param then
					schema = schem
					break
				end
			end
		end

		if schema then
			local count = 1
			local pos_offset = 0
			if schema.yadjust then pos_offset = schema.yadjust end

			local placement_pos = vector.offset(pos, x, pos_offset, z)
			local schematic = loadstring(schema.schem_lua)()
			create_ground_turnip(vector.offset(pos, x, -1, z), schematic["size"]["x"],
			                     schematic["size"]["z"], "Plains")

			offset = math.max(schematic["size"]["x"], schematic["size"]["z"]) * 2 + 3
			core.place_schematic(placement_pos, schematic, 0, nil, true, {
				place_center_x = true,
				place_center_y = false,
				place_center_z = true,
			})

			x = x + offset

			for biome_type, biome in pairs(mcl_villages.material_substitions) do
				count = count + 1
				placement_pos = vector.offset(pos, x, pos_offset, z)
				local modified_schem_lua = schema.schem_lua

				for _, sub in pairs(biome) do
					modified_schem_lua = modified_schem_lua:gsub(sub[1], sub[2])
				end

				schematic = loadstring(modified_schem_lua)()

				local biome_name = "Plains"
				if reverse_map[biome_type] then biome_name = reverse_map[biome_type] end

				create_ground_turnip(vector.offset(pos, x, -1, z), schematic["size"]["x"],
				                     schematic["size"]["z"], biome_name)

				core.place_schematic(placement_pos, schematic, 0, nil, true, {
					place_center_x = true,
					place_center_y = false,
					place_center_z = true,
				})

				if count % 4 == 0 then
					x = 10
					z = z + offset
				else
					x = x + offset
				end
			end
		end
	end,
})

local ground_padding = tonumber(core.settings:get("mcl_ground_padding")) or 1

-- Copied from Mineclonia to enable passing in the biome name
function create_ground_turnip(pos, fwidth, fdepth, biome_name)
	local reg_biome = core.registered_biomes[biome_name]

	local mat = "mcl_core:dirt"
	local filler = "mcl_core:dirt"
	local grass_idx = 0

	-- Use biome info if we have it
	if reg_biome and reg_biome.node_top then
		mat = reg_biome.node_top
		grass_idx = reg_biome._mcl_palette_index or 0
		if reg_biome.node_filler then
			filler = reg_biome.node_filler
			if core.get_item_group(filler, "material_sand") > 0 then
				if reg_biome.node_stone then filler = reg_biome.node_stone end
			end
		elseif reg_biome.node_stone then
			filler = reg_biome.node_stone
		end
	end

	local y = pos.y

	local radius = math.floor(((math.max(fwidth, fdepth)) / 2)) + ground_padding
	if radius <= 0 then return end

	-- usually we add 2 layers, each 2 blocks wider, then fill smaller layers below
	-- but for sand we add 2 layers 1 wider and then make the first fill layer wider
	-- otherwsie the sand can collapse and as funny as it is, it is annoying
	local needs_support = core.get_item_group(mat, "material_sand") > 0

	if needs_support then radius = radius + 1 end

	for _ = 1, 2 do
		if not needs_support then
			radius = radius + 2
		else
			radius = radius + 1
		end

		mcl_util.circle_bulk_set_node_vm(radius, pos, y, mat, grass_idx)
		y = y - 1
	end

	if needs_support then radius = radius + 2 end

	for _ = 1, 5 do
		radius = radius - 1

		if radius <= 2 then break end

		mcl_util.circle_bulk_set_node_vm(radius, pos, y, filler)
		y = y - 1
	end
end

local old_check_growth_simple = mcl_trees.check_growth_simple

local function check_growth_simple(pos, height)
	local ok = old_check_growth_simple(pos, height)
	if ok and world_settings.get(mod_name, "clear_leaves") == true then
		local leaves = core.find_nodes_in_area(pos, vector.offset(pos, 0, height, 0),
		                                       {"group:leaves", "mcl_core:vine"})
		if leaves then core.bulk_set_node(leaves, {name = "air"}) end
	end

	return ok
end

mcl_trees.check_growth_simple = check_growth_simple

if world_settings.get(mod_name, "split_quartz") then
	core.register_craft({
		output = "mcl_nether:quartz 4",
		recipe = {{"mcl_nether:quartz_block"}},
	})
end

local stack_max = world_settings.get(mod_name, "milk_bucket_stack")
if stack_max > 1 then core.override_item("mcl_mobitems:milk_bucket", {stack_max = stack_max}) end

if internal_api.has_tpad and world_settings.get(mod_name, "tpads_restyle") then
	core.clear_craft({type = "cooking", recipe = "tpad:tpad"})
	core.register_craft({
		output = "tpad:tpad",
		recipe = {
			{"mcl_core:gold_ingot", "mcl_core:iron_ingot", "mcl_core:gold_ingot"},
			{"mcl_core:iron_ingot", "mcl_core:lapis", "mcl_core:iron_ingot"},
			{"mcl_core:obsidian", "mcl_core:iron_ingot", "mcl_core:obsidian"},
		},
	})

	core.override_item("tpad:tpad", {
		tiles = {
			{
				name = "mcl_portals_portal.png",
				animation = {type = "vertical_frames", aspect_w = 8, aspect_h = 8, length = 1.25},
			},
			{
				name = "mcl_portals_portal.png",
				animation = {type = "vertical_frames", aspect_w = 8, aspect_h = 8, length = 1.25},
			},
			"default_gold_block.png",
			"default_gold_block.png",
			"default_gold_block.png",
			"default_gold_block.png",
		},
		drawtype = "nodebox",
		paramtype = "light",
		paramtype2 = "facedir",
		sunlight_propagates = true,
		use_texture_alpha = "blend",
		walkable = false,
		is_ground_content = false,
		drop = "",
		light_source = 8,
		post_effect_color = {a = 180, r = 51, g = 7, b = 89},
		node_box = {type = "fixed", fixed = {{-0.5, -0.5, -0.5, 0.5, -0.3, 0.5}}},
	})
end

if internal_api.has_tpad and world_settings.get(mod_name, "tpads_starter") then
	table.insert(mcl_bonus_chest.bonus_loot, {
		stacks_min = 1,
		stacks_max = 1,
		items = {{itemstring = "tpad:tpad", amount_min = 3, amount_max = 5}},
	})
end

-- Sneak + right click to get XP from furnace
if world_settings.get(mod_name, "furnace_xp_yoink") then
	core.override_item("mcl_furnaces:furnace", {
		_mcl_on_rightclick_optional = function(pos, node, player)
			if player and player:is_player() and not player.is_fake_player and
				player:get_player_control().sneak then
				if core.is_protected(pos, player:get_player_name()) then
					core.record_protection_violation(pos, player:get_player_name())
				else
					mcl_furnaces.give_xp(pos, player)
					return
				end
			end
		end,
	})

	core.override_item("mcl_furnaces:furnace_active", {
		_mcl_on_rightclick_optional = function(pos, node, player)
			if player and player:is_player() and not player.is_fake_player and
				player:get_player_control().sneak then
				if core.is_protected(pos, player:get_player_name()) then
					core.record_protection_violation(pos, player:get_player_name())
				else
					mcl_furnaces.give_xp(pos, player)
					return
				end
			end
		end,
	})
end

-- Allow using enchanted bow or crossbow for dispenser
core.register_craft({
	output = "mcl_dispensers:dispenser",
	recipe = {
		{"mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble"},
		{"mcl_core:cobble", "group:bow", "mcl_core:cobble"},
		{"mcl_core:cobble", "mcl_redstone:redstone", "mcl_core:cobble"},
	},
})

-- Capture mobs
if world_settings.get(mod_name, "bag_of_capture") then
	if internal_api.has_prestibags and internal_api.has_fireflies then
		core.register_tool("mcla_codihacks:bag_of_capture", {
			description = "Bag of catching mobs",
			groups = {flammable = 1},
			inventory_image = "prestibags_bag_inv.png^[transformFY",
			wield_image = "prestibags_bag_inv.png^[transformFY",
			stack_max = 1,

			on_secondary_use = function(itemstack, player, pointed_thing)
				local meta = itemstack:get_meta()
				local meta_sd = meta:get_string("static_data")
				local meta_mob = meta:get_string("mob")

				if meta_sd ~= "" and meta_mob ~= "" then return end

				if pointed_thing.type == "object" then
					local entity = pointed_thing.ref:get_luaentity()
					if entity and entity.is_mob then
						local sd = entity:get_staticdata()
						meta:set_string("static_data", sd)
						meta:set_string("mob", entity.name)
						entity:safe_remove()
						return itemstack
					end
				end
			end,
			on_use = function(itemstack, user, pointed_thing)
				local meta = itemstack:get_meta()
				local sd = meta:get_string("static_data")
				local mob = meta:get_string("mob")
				if sd ~= "" and mob ~= "" and pointed_thing.type == "node" then
					core.add_entity(pointed_thing.above, mob, sd)
					local meta = itemstack:get_meta()
					meta:set_string("static_data", "")
					meta:set_string("mob", "")
					return itemstack
				end
			end,
		})

		core.register_craft({
			output = "mcla_codihacks:bag_of_capture",
			recipe = {{"group:bag", "mcl_fireflies:bug_net"}},
		})
	else
		if not internal_api.has_prestibags then
			core.log("error",
			         "You have enabled the Bag of Capture but you do not have the prestibags mod enabled.")
		end
		if not internal_api.has_fireflies then
			core.log("error",
			         "You have enabled the Bag of Capture but you do not have the mcl_fireflies mod enabled.")
		end
	end
end

if world_settings.get(mod_name, "stripped_stairs") then
	local wood_types = {"bark_stripped", "stripped"}

	for name, def in pairs(mcl_trees.woods) do
		for _, wood_type in ipairs(wood_types) do
			local node_name = "mcl_trees:" .. wood_type .. "_" .. name
			local node_def = core.registered_nodes[node_name]
			if node_def then
				local trans_name = def.readable_name or node_name
				local stair_name = S("Stripped @1 Stairs", trans_name)
				local slab_name = S("Stripped @1 Slab", trans_name)

				if wood_type == "bark_stripped" then
					stair_name = S("Stripped @1 Bark Stairs", trans_name)
					slab_name = S("Stripped @1 Bark Slab", trans_name)
				end

				mcl_stairs.register_stair_and_slab(wood_type .. "_" .. name, {
					description_stair = stair_name,
					description_slab = slab_name,
					baseitem = node_name,
					groups = {wood_stairs = 1},
					overrides = {_mcl_burntime = 15},
				})
			end
		end
	end
end
