local internal_api = ...

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

local schem_path = mod_path .. "/schematics/"

local village_in_a_box = world_settings.get(mod_name, "village_in_a_box")
local graveyard = world_settings.get(mod_name, "graveyard")

local buildings = {}

buildings["graveyard"] = {
	name = "graveyard",
	mts = schem_path .. "graveyard.mts",
	num_others = 20,
	yadjust = -2,
}

buildings["village_in_a_box"] = {
	name = "village_in_a_box",
	mts = schem_path .. "village_in_a_box.mts",
	num_others = 20,
	yadjust = 1,
}

local function graveyard_zombie_spawn(settlement_info, blockseed)
	if world_settings.get(mod_name, "graveyard") then
		for _, def in pairs(settlement_info) do
			if def.name == "graveyard" then
				local pos = def.pos
				local nn = core.find_nodes_in_area(vector.offset(pos, -10, -5, -10),
				                                   vector.offset(pos, 10, 5, 10),
				                                   "mcl_mobspawners:spawner")
				for _, n in pairs(nn) do
					mcl_mobspawners.setup_spawner(n, "mobs_mc:zombie", 0, 11, 5, 10, 1)
				end
			end
		end
	end
end

function indexOf(array, value)
	for i, v in ipairs(array) do if v.name == value then return i end end
	return nil
end

local function switch_building(enabled, name, type)
	local village_table = "schematic_jobs"
	if type and type == "house" then village_table = "schematic_houses" end

	local i = indexOf(mcl_villages[village_table], name)

	if enabled then
		if i == nil then mcl_villages.register_building(buildings[name]) end
	else
		if i then table.remove(mcl_villages[village_table], i) end
	end
end

switch_building(village_in_a_box, "village_in_a_box")
switch_building(graveyard, "graveyard", "house")

-- /locate structure mcl_levelgen:pillager_outpost
-- /locate structure mcl_villages:village_snowy
-- plains, taiga, snowy, desert, savannah
if world_settings.get(mod_name, "bee_farm") and mcl_villages.register_building_v2 ~= nil then
	mcl_villages.register_building_v2(mod_name .. ":bee_farm", {
		type = "junction",
		list = "job_buildings",
		file = mod_path .. "/schematics/bee_farm.mts",
		variants = {"plains", "savannah"},
		weight = {plains = 1, savannah = 1},
	})

	mcl_villages.register_building_v2(mod_name .. ":bee_farm_snowy", {
		type = "junction",
		list = "job_buildings",
		file = mod_path .. "/schematics/bee_farm_snowy.mts",
		variants = {"snowy", "taiga"},
		weight = {snowy = 1, taiga = 1},
	})

	mcl_villages.register_building_v2(mod_name .. ":bee_farm_desert", {
		type = "junction",
		list = "job_buildings",
		file = mod_path .. "/schematics/bee_farm_desert.mts",
		variants = {"desert"},
		weight = {desert = 1},
	})
end

-- Removed annoying popup
local function discovery_popup(player, pos, data, waypoint_def)
	local player_name = player:get_player_name()
	local discovery_name = data.name or waypoint_def.default_name
	local discovery_note = S("You have discovered @1", discovery_name)
	core.chat_send_player(player_name, discovery_note)
	core.sound_play({name = "named_waypoints_chime01", gain = 0.25}, {to_player = player_name})
end

-- Add village names and waypoints
local function update_waypoint_def(discovery_distance, waypoint_distance)
	if internal_api.has_named_waypoints then
		local village_waypoint_def = {
			default_name = S("A village"),
			default_color = 0x49A0F6,
			discovery_volume_radius = discovery_distance,
			on_discovery = discovery_popup,
			visibility_volume_radius = waypoint_distance,
		}

		named_waypoints.register_named_waypoints("mingos towns", village_waypoint_def)
	end
end

update_waypoint_def(world_settings.get(mod_name, "village_discovery_distance"),
                    world_settings.get(mod_name, "village_waypoint_distance"))

if internal_api.has_name_generator then
	local name_generator_mod_path = core.get_modpath("name_generator")
	name_generator.parse_lines(io.lines(name_generator_mod_path .. "/data/towns.cfg"))
	name_generator.parse_lines(io.lines(name_generator_mod_path .. "/data/creatures.cfg"))
end

local function name_village(settlement_info, blockseed)
	if internal_api.has_name_generator and internal_api.has_named_waypoints and
		world_settings.get(mod_name, "name_villages") then
		local name = name_generator.generate("mingos towns")
		local bell_info = table.copy(settlement_info[1])
		named_waypoints.add_waypoint("mingos towns", vector.offset(bell_info["pos"], 0, 2, 0),
		                             {name = name})
	end
end

-- Add villager names
local races = {"dwarf", "elf", "gnome", "halfling", "human"}

local genders = {"female", "male"}

local pad_str = S("TPAD Village Station - right click to interact")

local function name_villager(villager_ent, blockseed)
	if internal_api.has_name_generator and world_settings.get(mod_name, "name_villagers") then
		local pr = PseudoRandom(blockseed)
		local l = villager_ent:get_luaentity()
		local name_type = races[pr:next(1, #races)] .. " " .. genders[pr:next(1, #genders)]
		l.nametag = name_generator.generate(name_type)
		l.object:set_nametag_attributes({text = l.nametag})
	end
end

local function add_tpad(settlement_info, blockseed)
	if internal_api.has_tpad and world_settings.get(mod_name, "tpads_for_villages") then
		local bell_info = table.copy(settlement_info[1])

		local flag_pos = vector.offset(bell_info["pos"], 0, 2, 0)

		local pad_name = "Town Pad"

		if internal_api.has_name_generator and internal_api.has_named_waypoints and
			world_settings.get(mod_name, "name_villages") then
			local data = named_waypoints.get_waypoint("mingos towns", flag_pos)
			if data and data.name then pad_name = data.name end
		end

		local pos = vector.offset(bell_info["pos"], -1, 2, 0)
		core.set_node(pos, {name = "tpad:tpad"})

		local meta = core.get_meta(pos)
		meta:set_string("owner", "Villages")
		meta:set_string("infotext", pad_str)
		tpad.set_pad_data(pos, pad_name, "Global (any network)")
	end
end

local function name_villager_new(villager, ull)
	if internal_api.has_name_generator and world_settings.get(mod_name, "name_villagers") then
		local pr = PseudoRandom(ull[1])
		local name_type = races[pr:next(1, #races)] .. " " .. genders[pr:next(1, #genders)]
		villager.nametag = name_generator.generate(name_type)
		villager.object:set_nametag_attributes({text = villager.nametag})
	end
end

local function handle_spawn_iron_golem(name, data)
	local village_name
	local pos = vector.new(mcl_levelgen.level_to_minetest_position(data[1], data[2], data[3]))

	local min = vector.round(vector.offset(pos, -3, -3, -3))
	local max = vector.round(vector.offset(pos, 3, 3, 3))
	local nn = core.find_nodes_in_area(min, max, {"mcl_bells:bell"})

	if #nn > 0 then
		local bell = nn[1]

		if internal_api.has_name_generator and internal_api.has_named_waypoints and
			world_settings.get(mod_name, "name_villages") then
			village_name = name_generator.generate("mingos towns")
			named_waypoints.add_waypoint("mingos towns", bell, {name = village_name})
		end

		if internal_api.has_tpad and world_settings.get(mod_name, "tpads_for_villages") then
			local pad_name = "Town Pad"

			if village_name then pad_name = village_name end

			local pad_pos = vector.round(vector.offset(bell, 0, -3, 0))
			core.set_node(pad_pos, {name = "tpad:tpad"})

			local meta = core.get_meta(pad_pos)
			meta:set_string("owner", "Villages")
			meta:set_string("infotext", pad_str)
			tpad.set_pad_data(pad_pos, pad_name, "Global (any network)")
		end
	end

	local gol_pos = vector.offset(pos, 0, -0.5, 0)
	core.add_entity(gol_pos, "mobs_mc:iron_golem")
end

if mcl_levelgen.register_notification_handler ~= nil then
	mcl_villages.register_on_villager_spawned(name_villager_new)
	-- Don't like this as it replaces the real one ...
	mcl_levelgen.register_notification_handler("mcl_villages:spawn_iron_golem",
	                                           handle_spawn_iron_golem)
elseif mcl_villages.on_village_placed ~= nil then
	-- Remove this and the functions they call after we no longer want to support older Mineclonia versions
	mcl_villages.register_on_village_placed(name_village)
	mcl_villages.register_on_villager_spawned(name_villager)
	mcl_villages.register_on_village_placed(graveyard_zombie_spawn)
	mcl_villages.register_on_village_placed(add_tpad)
end

-- TODO switch_building probably no longer works
core.register_on_chatcommand(function(name, command, params)
	if command ~= "wset" or params == "" or core.check_player_privs(name, {server = false}) then
		return
	end

	local sparam = params:split(" ")
	local key = sparam[1]
	local value = sparam[2]

	if key == mod_name .. ".village_in_a_box" then
		switch_building(value == "true", "village_in_a_box")
	elseif key == mod_name .. ".graveyard" then
		switch_building(value == "true", "graveyard", "house")
	elseif key == mod_name .. ".village_discovery_distance" then
		update_waypoint_def(value, world_settings.get(mod_name, "village_waypoint_distance"))
	elseif key == mod_name .. ".village_waypoint_distance" then
		update_waypoint_def(world_settings.get(mod_name, "village_discovery_distance"), value)
	end
end)
