-- LUALOCALS < ---------------------------------------------------------
local ItemStack, math, minetest, nodecore, pairs, vector
    = ItemStack, math, minetest, nodecore, pairs, vector
local math_floor, math_random
    = math.floor, math.random
-- LUALOCALS > ---------------------------------------------------------

local cache = {}

function nodecore.item_ent_merge(pos)
	pos = vector.round(pos)
	local hash = minetest.hash_node_position(pos)

	local t = cache[hash]
	if t and t > nodecore.gametime then return end
	cache[hash] = (t or nodecore.gametime) + 0.75 + 0.5 * math_random()

	local db = {}
	for _, obj in pairs(minetest.get_objects_inside_radius(pos, 1)) do
		if vector.equals(vector.round(obj:get_pos()), pos) then
			local lua = obj.get_luaentity and obj:get_luaentity()
			if lua and lua.name == "__builtin:item" then
				local stack = ItemStack(lua.itemstring or "")
				if not stack:is_empty() then
					local qty = stack:get_count()
					stack:set_count(1)
					local key = stack:to_string()
					local entry = db[key]
					if entry then
						entry.qty = entry.qty + qty
						entry.objs[#entry.objs + 1] = {obj = obj, lua = lua}
					else
						db[key] = {
							stack = stack,
							qty = qty,
							objs = {{obj = obj, lua = lua}}
						}
					end
				end
			end
		end
	end
	for _, entry in pairs(db) do
		if #entry.objs > 1 then
			local stack = entry.stack
			local qty = entry.qty
			local max = stack:get_stack_max()
			local stax = math_floor((qty + max - 1) / max)
			if stax < #entry.objs then
				for _, item in pairs(entry.objs) do
					if qty > 0 then
						local num = qty > max and max or qty
						stack:set_count(num)
						item.lua:set_item(stack)
						qty = qty - num
					else
						item.obj:remove()
					end
				end
			end
		end
	end
end
