local S = minetest.get_translator("hades_hunger")

local mod_simulation = minetest.get_modpath("hades_simulation") ~= nil

-- wrapper for minetest.item_eat (this way we make sure other mods can't break this one)
minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
	-- Check if the item's 'eatable' group is valid
	hades_hunger.check_eatable_group(itemstack, hp_change)

	local old_itemstack = itemstack
	itemstack = hades_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
	for _, callback in pairs(minetest.registered_on_item_eats) do
		local result = callback(hp_change, replace_with_item, itemstack, user, pointed_thing, old_itemstack)
		if result then
			return result
		end
	end
	return itemstack
end

local play_eat_sound = function(player, sound)
	minetest.sound_play(
		{name = sound or "hbhunger_eat_generic",
		gain = 1},
		{object=player,
		max_hear_distance = 16,
		pitch = 1 + math.random(-10, 10)*0.005,},
		true
	)
end

function hades_hunger.eat(hp_change, replace_with_item, itemstack, user, pointed_thing)
	local item = itemstack:get_name()

	local def = {}


	if type(hp_change) ~= "number" then
		hp_change = 1
		minetest.log("error", "[hades_hunger] Wrong on_use() definition for item '" .. item .. "'")
	end

	def.saturation = hp_change
	def.replace = replace_with_item

	local sound = def.sound
	if not sound then
		if minetest.get_item_group(item, "food") == 3 then
			sound = "survival_thirst_drink"
		elseif not sound then
			sound = "hbhunger_eat_generic"
		end
	end
	if mod_simulation and hades_simulation.is_in_simulation(user) then
		-- If eating in simulation, consume item but don't apply food effects
		play_eat_sound(user, sound)
		local name = user:get_player_name()
		local creative = minetest.is_creative_enabled(name)
		if not creative then
			local take = itemstack:take_item()
			if not take then
				return itemstack
			end
			if itemstack:get_count() == 0 then
				itemstack:add_item(replace_with_item)
			else
				local inv = user:get_inventory()
				if inv:room_for_item("main", replace_with_item) then
					inv:add_item("main", replace_with_item)
				else
					minetest.add_item(user:get_pos(), replace_with_item)
				end
			end
		end
		return itemstack
	end
	local func = hades_hunger.item_eat(def.saturation, def.replace, def.healing, sound)
	return func(itemstack, user, pointed_thing)
end

function hades_hunger.item_eat(hunger_change, replace_with_item, heal, sound)
	return function(itemstack, user, pointed_thing)
		if user ~= nil then
			local name = user:get_player_name()
			local creative = minetest.is_creative_enabled(name)
			if not creative then
				local take = itemstack:take_item()
				if not take then
					return itemstack
				end
			end
			local h = tonumber(hades_hunger.hunger[name])
			local hp = user:get_hp()
			if h == nil or hp == nil then
				return
			end
			play_eat_sound(user, sound)

			-- Saturation
			if h < hades_hunger.SAT_MAX and hunger_change then
				h = h + hunger_change
				if h > hades_hunger.SAT_MAX then h = hades_hunger.SAT_MAX end
				hades_hunger.hunger[name] = h
				hades_hunger.set_hunger_raw(user)
			end
			-- Healing
			if hp < 20 and heal then
				hp = hp + heal
				if hp > 20 then hp = 20 end
				player:set_hp(hp, {type="set_hp", from="mod", _custom_reason="hunger"})
			end

			if not creative then
				if itemstack:get_count() == 0 then
					itemstack:add_item(replace_with_item)
				else
					local inv = user:get_inventory()
					if inv:room_for_item("main", replace_with_item) then
						inv:add_item("main", replace_with_item)
					else
						minetest.add_item(user:get_pos(), replace_with_item)
					end
				end
			end
		end
		return itemstack
	end
end

-- Increase player exhaustion by the given value.
-- If exhaustion reaches a certain threshold, player
-- loses 1 satiation point and exhaustion is reset to 0.
function hades_hunger.exhaust(player, exhaustion_add)
	if not player or not player:is_player() or player.is_fake_player == true then
		return
	end
	local name = player:get_player_name()
	local exhaus = hades_hunger.exhaustion[name]
	if not exhaus then
		return
	end
	exhaus = exhaus + exhaustion_add
	if exhaus > hades_hunger.EXHAUST_LVL then
		exhaus = 0
		local h = tonumber(hades_hunger.hunger[name])
		h = h - 1
		if h < 0 then h = 0 end
		hades_hunger.hunger[name] = h
		hades_hunger.set_hunger_raw(player)
	end
	hades_hunger.exhaustion[name] = exhaus
end

-- player-action based hunger changes
function hades_hunger.handle_node_actions(pos, oldnode, player, ext)
	-- is_fake_player comes from the pipeworks, we are not interested in those
	if not player or not player:is_player() or player.is_fake_player == true then
		return
	end
	local name = player:get_player_name()
	local exhaus = hades_hunger.exhaustion[name]
	if not exhaus then
		return
	end
	local new = hades_hunger.EXHAUST_PLACE
	-- placenode event
	if not ext then
		new = hades_hunger.EXHAUST_DIG
	end
	hades_hunger.exhaust(player, new)
end

minetest.register_on_placenode(hades_hunger.handle_node_actions)
minetest.register_on_dignode(hades_hunger.handle_node_actions)
