local minetest_after      = minetest.after
local minetest_sound_play = minetest.sound_play
local minetest_dir_to_yaw = minetest.dir_to_yaw

local math = math
local vector = vector

local MAX_MOB_NAME_LENGTH = 30

local mod_hunger = minetest.get_modpath("mcl_hunger")

mobs.feed_tame = function(self)
    return nil
end

-- Code to execute before custom on_rightclick handling
local function on_rightclick_prefix(self, clicker)
	local item = clicker:get_wielded_item()

	-- Name mob with nametag
	if not self.ignores_nametag and item:get_name() == "mcl_mobs:nametag" then

		local tag = item:get_meta():get_string("name")
		if tag ~= "" then
			if string.len(tag) > MAX_MOB_NAME_LENGTH then
				tag = string.sub(tag, 1, MAX_MOB_NAME_LENGTH)
			end
			self.nametag = tag

			mobs.update_tag(self)

			if not mobs.is_creative(clicker:get_player_name()) then
				item:take_item()
				clicker:set_wielded_item(item)
			end
			return true
		end

	end
	return false
end

-- I have no idea what this does
mobs.create_mob_on_rightclick = function(on_rightclick)
	return function(self, clicker)
		--don't allow rightclicking dead mobs
		if self.health <= 0 then
			return
		end
		local stop = on_rightclick_prefix(self, clicker)
		if (not stop) and (on_rightclick) then
			on_rightclick(self, clicker)
		end
	end
end


-- deal damage and effects when mob punched
mobs.mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
	--don't do anything if the mob is already dead
	if self.health <= 0 then
		return
	end

	--neutral passive mobs switch to neutral hostile
	if self.neutral then
		--drop in variables for attacking (stops crash)
		self.attacking   = hitter
		self.punch_timer = 0
		self.hostile = true
		--hostile_cooldown timer is initialized here
		self.hostile_cooldown_timer = self.hostile_cooldown

		--initialize the group attack (check for other mobs in area, make them neutral hostile)
		if self.group_attack then
			mobs.group_attack_initialization(self)
		end
	end

	--turn skittish mobs away and RUN
	if self.skittish then

		self.state = "run"

		self.run_timer = 5 --arbitrary 5 seconds

		local pos1 = self.object:get_pos()
		pos1.y = 0
		local pos2 = hitter:get_pos()
		pos2.y = 0


		local dir = vector.direction(pos2,pos1)

		local yaw = minetest_dir_to_yaw(dir)

		self.yaw = yaw
	end

	-- custom punch function
	if self.do_punch then
		-- when false skip going any further
		if self.do_punch(self, hitter, tflp, tool_capabilities, dir) == false then
			return
		end
	end

	--don't do damage until pause timer resets
	if self.pause_timer > 0 then
		return
	end

	-- error checking when mod profiling is enabled
	if not tool_capabilities then
		minetest.log("warning", "[mobs_mc] Mod profiling enabled, damage not enabled")
		return
	end

	local is_player = hitter:is_player()

	-- punch interval
	local weapon = hitter:get_wielded_item()

	--local punch_interval = 1.4

	-- exhaust attacker
	if mod_hunger and is_player then
		mcl_hunger.exhaust(hitter:get_player_name(), mcl_hunger.EXHAUST_ATTACK)
	end

	-- calculate mob damage
	local damage = 0
	local armor = self.object:get_armor_groups() or {}

	--calculate damage groups
	for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do
		damage = damage + (tool_capabilities.damage_groups[group] or 0) * ((armor[group] or 0) / 100.0)
	end

	if weapon then
		local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect")
		if fire_aspect_level > 0 then
			mcl_burning.set_on_fire(self.object, fire_aspect_level * 4)
		end
	end

	-- check for tool immunity or special damage
	for n = 1, #self.immune_to do
		if self.immune_to[n][1] == weapon:get_name() then
			damage = self.immune_to[n][2] or 0
			break
		end
	end

	-- healing
	if damage <= -1 then
		self.health = self.health - math.floor(damage)
		return
	end

	--if tool_capabilities then
	--	punch_interval = tool_capabilities.full_punch_interval or 1.4
	--end

	-- add weapon wear manually
	-- Required because we have custom health handling ("health" property)
	--minetest_is_creative_enabled("") ~= true --removed for now
	if tool_capabilities then
		if tool_capabilities.punch_attack_uses then
			-- Without this delay, the wear does not work. Quite hacky ...
			minetest_after(0, function(name)
				local player = minetest.get_player_by_name(name)
				if not player then return end
				local weapon = hitter:get_wielded_item(player)
				local def = weapon:get_definition()
				if def.tool_capabilities and def.tool_capabilities.punch_attack_uses then
					local wear = math.floor(65535/tool_capabilities.punch_attack_uses)
					weapon:add_wear(wear)
					hitter:set_wielded_item(weapon)
				end
			end, hitter:get_player_name())
		end
	end


	--if player is falling multiply damage by 1.5
	--critical hit
	local hitter_velocity = hitter:get_velocity() or hitter:get_player_velocity() or vector.new(0, 0, 0)
	if hitter_velocity.y < 0 then
		damage = damage * 1.5
		mobs.critical_effect(self)
	end


	-- only play hit sound and show blood effects if damage is 1 or over; lower to 0.1 to ensure armor works appropriately.
	if damage >= 0.1 then

		minetest_sound_play("default_punch", {
			object = self.object,
			max_hear_distance = 16
		}, true)

		-- do damage
		self.health = self.health - damage


		--0.4 seconds until you can hurt the mob again
		self.pause_timer = 0.4

		--don't do knockback from a rider
		local object_children = self.object.get_children and self.object:get_children()
		-- TODO: support 5.1.1
		for _,obj in pairs(object_children or {}) do
			if obj == hitter then
				return
			end
		end

		-- knock back effect
		local velocity = self.object:get_velocity()

		--2d direction
		local pos1 = self.object:get_pos()
		pos1.y = 0
		local pos2 = hitter:get_pos()
		pos2.y = 0

		local dir = vector.direction(pos2,pos1)

		local up = 3

		-- if already in air then dont go up anymore when hit
		if velocity.y ~= 0 then
			up = 0
		end

		--0.75 for perfect distance to not be too easy, and not be too hard
		local multiplier = 0.75

		-- check if tool already has specific knockback value
		local knockback_enchant = mcl_enchanting.get_enchantment(hitter:get_wielded_item(), "knockback")
		if knockback_enchant and knockback_enchant > 0 then
			multiplier = knockback_enchant + 1 --(starts from 1, 1 would be no change)
		end

		--do this to sure you can punch a mob back when
		--it's coming for you
		if self.hostile then
			multiplier = multiplier + 2
		end
		dir = vector.multiply(dir,multiplier)
		dir.y = up
		--add the velocity
		self.object:add_velocity(dir)
	end
end

--do internal per mob projectile calculations
mobs.shoot_projectile = function(self)
	local pos1 = self.object:get_pos()
	--add mob eye height
	pos1.y = pos1.y + self.eye_height

	local pos2 = self.attacking:get_pos()
	--add player eye height
	pos2.y = pos2.y + self.attacking:get_properties().eye_height

	--get direction
	local dir = vector.direction(pos1,pos2)

	--call internal shoot_arrow function
	self.shoot_arrow(self,pos1,dir)
end

mobs.update_tag = function(self)
	self.object:set_properties({
		nametag = self.nametag,
	})
end