local S = minetest.get_translator(minetest.get_current_modname())
local storage = mcl_portals.storage

local vector = vector

local gateway_positions = {
	{x = 96, y = -26925, z = 0},
	{x = 91, y = -26925, z = 29},
	{x = 77, y = -26925, z = 56},
	{x = 56, y = -26925, z = 77},
	{x = 29, y = -26925, z = 91},
	{x = 0, y = -26925, z = 96},
	{x = -29, y = -26925, z = 91},
	{x = -56, y = -26925, z = 77},
	{x = -77, y = -26925, z = 56},
	{x = -91, y = -26925, z = 29},
	{x = -96, y = -26925, z = 0},
	{x = -91, y = -26925, z = -29},
	{x = -77, y = -26925, z = -56},
	{x = -56, y = -26925, z = -77},
	{x = -29, y = -26925, z = -91},
	{x = 0, y = -26925, z = -96},
	{x = 29, y = -26925, z = -91},
	{x = 56, y = -26925, z = -77},
	{x = 77, y = -26925, z = -56},
	{x = 91, y = -26925, z = -29},
}

local path_gateway_portal = minetest.get_modpath("mcl_structures").."/schematics/mcl_structures_end_gateway_portal.mts"

local function spawn_gateway_portal(pos, dest_str)
	return mcl_structures.place_schematic(vector.add(pos, vector.new(-1, -2, -1)), path_gateway_portal, "0", nil, true, nil, dest_str and function()
		minetest.get_meta(pos):set_string("mcl_portals:gateway_destination", dest_str)
	end)
end

function mcl_portals.spawn_gateway_portal()
	local id = storage:get_int("gateway_last_id") + 1
	local pos = gateway_positions[id]
	if not pos then return end
	storage:set_int("gateway_last_id", id)
	spawn_gateway_portal(pos)
end

local gateway_def = table.copy(minetest.registered_nodes["mcl_portals:portal_end"])
gateway_def.description = S("End Gateway Portal")
gateway_def._tt_help = S("Used to construct end gateway portals")
gateway_def._doc_items_longdesc = S("An End gateway portal teleports creatures and objects to the outer End (and back!).")
gateway_def._doc_items_usagehelp = S("Throw an ender pearl into the portal to teleport. Entering an Gateway portal near the Overworld teleports you to the outer End. At this destination another gateway portal will be constructed, which you can use to get back.")
gateway_def.after_destruct = nil
gateway_def.drawtype = "normal"
gateway_def.node_box = nil
gateway_def.walkable = false
gateway_def.tiles[3] = nil
gateway_def.collision_box = nil

local function find_destination_pos(minp, maxp)
	for y = maxp.y, minp.y, -1 do
		for x = maxp.x, minp.x, -1 do
			for z = maxp.z, minp.z, -1 do
				local pos = vector.new(x, y, z)
				local nn = minetest.get_node(pos).name
				if nn ~= "ignore" and nn ~= "mcl_portals:portal_gateway" and nn ~= "mcl_core:bedrock" then
					local def = minetest.registered_nodes[nn]
					if def and def.walkable then
						return vector.add(pos, vector.new(0, 1.5, 0))
					end
				end
			end
		end
	end
end

local preparing = {}

local function teleport(pos, obj)
	local meta = minetest.get_meta(pos)
	local dest_portal
	local dest_str = meta:get_string("mcl_portals:gateway_destination")
	local pos_str = minetest.pos_to_string(pos)
	if dest_str == "" then
		dest_portal = vector.multiply(vector.direction(vector.new(0, pos.y, 0), pos), math.random(768, 1024))
		dest_portal.y = -26970
		spawn_gateway_portal(dest_portal, pos_str)
		meta:set_string("mcl_portals:gateway_destination", minetest.pos_to_string(dest_portal))
	else
		dest_portal = minetest.string_to_pos(dest_str)
	end
	local minp = vector.subtract(dest_portal, vector.new(5, 40, 5))
	local maxp = vector.add(dest_portal, vector.new(5, 10, 5))
	preparing[pos_str] = true
	minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining, param)
		if calls_remaining < 1 then
			if obj and obj:is_player() or obj:get_luaentity() then
				obj:set_pos(find_destination_pos(minp, maxp) or vector.add(dest_portal, vector.new(0, 3.5, 0)))
			end
			preparing[pos_str] = false
		end
	end)
end

-- Handle ender pearl collision with gateway portal for immediate teleportation
gateway_def._vl_projectile = {
	on_collide = function(self, pos, node, node_def)
		if self.name == "mcl_throwing:ender_pearl_entity" then
			local thrower = self._owner and minetest.get_player_by_name(self._owner)
			if thrower then
				self.object:remove()
				teleport(pos, thrower)
			end
		end
	end,
}
minetest.register_node("mcl_portals:portal_gateway", gateway_def)

minetest.register_abm({
	label = "End gateway portal teleportation",
	nodenames = {"mcl_portals:portal_gateway"},
	interval = 0.1,
	chance = 1,
	action = function(pos)
		if preparing[minetest.pos_to_string(pos)] then return end
		for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do
			if obj:get_hp() > 0 then
				teleport(pos, obj)
				return
			end
		end
	end,
})
