local mod_name = core.get_current_modname()
local mod_path = core.get_modpath(mod_name)
local S = core.get_translator(mod_name)

local function alert_nearby(self, dist)
	if not dist then dist = 30 end
	local nearby_objects = core.get_objects_inside_radius(self.object:get_pos(), dist)
	for _, object in pairs(nearby_objects) do
		local ent = object:get_luaentity()
		if ent and (not ent._aom_target)
		and (ent.name == "aom_animals:pipslug") then
			ent._aom_target = self._aom_target
		end
	end
end

local function do_sound(self, spec, gain)
	core.sound_play(spec, {
		gain = gain,
		object = self.object,
		pitch = 0.9 + math.random()*0.2,
		max_hear_distance = 20,
	})
end

local function do_dig_particles(pos)
	core.add_particlespawner({
		amount = 20,
		time = 0.0001,
		pos = pos,
		vel = {
			min = vector.new(-0.5,  0.2, -0.5) * 4,
			max = vector.new( 0.5,  1.5,    0.5) * 4,
		},
		acc = vector.new(0, -9, 0),
		texpool = {
			{
				name = "aom_muskets_smoke.png^[colorize:#2f2f2f:255",
			},
			{
				name = "aom_muskets_smoke.png^[colorize:#413932:255",
			},
		},
		collisiondetection = true,
		drag = vector.new(2, 1, 2),
		minsize = 1.2,
		maxsize = 6,
		minexptime = 1.1,
		maxexptime = 1.8,
	})
end

local state_optionlist = ExtraClasses.OptionList.new({
	{"transit_in", 1},
	{"move", 1},
	{"spit", 5},
}, math.random)

local state_optionlist_close = ExtraClasses.OptionList.new({
	{"transit_in", 3},
	{"spit", 1},
}, math.random)

aom_animals.pipslug = {
	initial_properties = {
		visual = "mesh",
		mesh = "aom_animals_pipslug.b3d",
		textures = {"aom_animals_pipslug.png"},
		use_texture_alpha = false,
		stepheight = 1.1,
		hp_max = 10,
		physical = true,
		collide_with_objects = false,
		collisionbox = {-0.4, 0.0, -0.4, 0.4, 0.5, 0.4},
		selectionbox = {-0.3, 0.0, -0.3, 0.3, 0.5, 0.3},
		pointable = true,
		damage_texture_modifier = "^[colorize:#ff9999:50",
		static_save = false,
	},
	_name = "aom_animals:pipslug",

	on_step = aom_entity_api.do_states(),

	_get_transit_pos = function(self, home, range, groups)
		home = home or self._aom_home_pos
		range = range or 20
		groups = groups or {"group:soil"}
		local yaw = math.random() * math.pi * 2
		local offset = core.yaw_to_dir(yaw)
		offset = offset * (math.random() * range * 0.9 + range * 0.1)
		local pos = home + offset
		local candidates = core.find_nodes_in_area_under_air(
			vector.offset(pos, -1, -5, 0), vector.offset(pos, 0, 5, 1), groups
		)
		local p = candidates[math.random(1, #candidates)]
		if not p then return end
		p.y = p.y + 1
		return p
	end,

	_drop = {
		max_items = 12,
        minmax = {
            {min = 1, max = 4,  item = "aom_flora:aelum_grass_seeds"},
            {min = 2, max = 8,  item = "aom_items:ignis"},
			{min = 1, max = 2,	item = "aom_animals:animal_meat"},
        },
	},
	on_death = function(self, killer)
	end,
	_states = {
		on_step = function(self, dtime, moveresult)
			if not self.object:get_pos() then
				return "death"
			end
			aom_entity_api.has_los_to_object(self, self._aom_target)
			if self._aom_target then
				self._aom_speed = 6
			else
				self._aom_speed = 4
			end

			aom_entity_api.decelerate(self, 0.97)

			if self._has_los_to_target then
				self._aom_time_since_los = 0
			else
				self._aom_time_since_los = (self._aom_time_since_los or 0) + dtime
				if self._aom_time_since_los > 3 then
					self._aom_target = nil
				end
			end

			if self._state ~= "death" then
				local in_or_above_water = aom_entity_api.float_in_liquids(self, dtime * 20, {offset=vector.new(0, 1.2, 0)})
				if not in_or_above_water then
					aom_entity_api.apply_gravity(self, dtime)
				end
			end
		end,
		idle = {
			animation = "idle",
			on_state_start = function(self)
				-- do_sound(self, "aom_animals_pipslug_".."idle", 1)
			end,
			step = function(self, dtime, moveresult)
				aom_entity_api.decelerate(self, 0.9)
				aom_entity_api.get_target(self, nil, {no_to_pos=false})
				if self._aom_state_time > 0.1 then
					if self._aom_target then
						local dist = aom_entity_api.get_target_dist(self)
						if dist and (dist < 6) then
							return state_optionlist_close:get_random()
						else
							return state_optionlist:get_random()
						end
					end
					return "move"
				end
			end,
		},
		move = {
			animation = "move",
			on_state_start = function(self)
				if self._aom_target then
					self._aom_time_until_idle = math.random() * 1 + 1
				else
					self._aom_time_until_idle = math.random() * 7 + 2
				end
				self._aom_goto_pos = nil
				for i = 0, 10 do
					if self._aom_goto_pos then break end
					self._aom_goto_pos = aom_animals.pipslug._get_transit_pos(self, nil, nil, {"group:solid"})
				end
				do_sound(self, "aom_animals_pipslug_".."sing", 1)
			end,
			on_state_end = function(self)
				self._aom_time_until_idle = nil
				self._aom_goto_pos = nil
			end,
			step = function(self, dtime, moveresult)
				if not self._aom_goto_pos then return "idle" end
				local pos = self.object:get_pos()
				local tpos = vector.copy(self._aom_goto_pos)
				tpos.y = pos.y
				local dist = vector.distance(pos, tpos)
				local dir = vector.direction(pos, tpos)
				local is_at_dest = (dist < 0.5)
				if not is_at_dest then
					local vel = self.object:get_velocity()
					local y = vel.y
					vel = dir * self._aom_speed
					vel.y = y
					self.object:set_velocity(vel)
				end
				aom_entity_api.decelerate(self, 0.5)
				if not self._aom_target then
					aom_entity_api.get_target(self, nil, {no_to_pos=false})
				end
				aom_entity_api.rotate_to_position(self, self._aom_goto_pos, dtime*2)
				if (is_at_dest and self._aom_state_time > 1) or (self._aom_state_time > self._aom_time_until_idle) then
					if self._aom_target then
						local tdist = aom_entity_api.get_target_dist(self)
						if tdist and (tdist < 6) then
							return state_optionlist_close:get_random()
						else
							return state_optionlist:get_random()
						end
					else
						return "idle"
					end
				end
			end,
		},
		transit_in = {
			animation = "dig_in",
			on_state_start = function(self)
				do_sound(self, "aom_animals_pipslug_".."sing", 1)
			end,
			on_state_end = function(self)
				self._aom_did_dig_in_particles = nil
			end,
			step = function(self, dtime, moveresult)
				aom_entity_api.decelerate(self, 0.9)
				local alen = aom_entity_api.get_current_animation_length(self)
				if (not self._aom_did_dig_in_particles) and (self._aom_state_time > (35 / alen)) then
					self._aom_did_dig_in_particles = true
					do_dig_particles(self.object:get_pos())
				end
				if self._aom_state_time > (60 / alen) then
					return "transit_idle"
				end
			end,
		},
		transit_idle = {
			animation = "dig_idle",
			on_state_start = function(self)
				self._aom_time_until_next = math.random() * 3 + 0.1
				local target_pos = aom_animals.pipslug._get_transit_pos(self)
				if not target_pos then return end
				self.object:set_pos(target_pos)
			end,
			step = function(self, dtime, moveresult)
				aom_entity_api.decelerate(self, 0.9)
				if self._aom_state_time > self._aom_time_until_next then
					return "transit_out"
				end
			end,
		},
		transit_out = {
			animation = "dig_out",
			on_state_start = function(self)
				do_dig_particles(self.object:get_pos())
			end,
			step = function(self, dtime, moveresult)
				aom_entity_api.decelerate(self, 0.9)
				if self._aom_state_time > (34 / aom_entity_api.get_current_animation_length(self)) then
					do_sound(self, "aom_animals_pipslug_".."sing", 1)
					return "idle"
				end
			end,
		},
		spit = {
			animation = "spit",
			on_state_start = function(self)
				if not self._aom_target then return end
				self._aom_aim_pos = self._aom_target:get_pos()
				if not self._aom_aim_pos then return end
				do_sound(self, "aom_animals_pipslug_".."distress", 1)
				self._aom_spitting = true
			end,
			step = function(self, dtime, moveresult)
				if not (self._aom_target and self._aom_aim_pos) then return "idle" end
				aom_entity_api.decelerate(self, 0.9)
				if self._aom_state_time < 2 then
					aom_entity_api.rotate_to_target(self, dtime*2)
				end
				if self._aom_state_time > (49 / aom_entity_api.get_current_animation_length(self)) then
					return "idle"
				end

				if self._aom_state_time < (30 / aom_entity_api.get_current_animation_length(self)) then
					self._aom_aim_pos = self._aom_target:get_pos()
				end

				if self._aom_spitting and self._aom_state_time > (37 / aom_entity_api.get_current_animation_length(self)) then repeat
					self._aom_spitting = nil
					local pos = vector.offset(self.object:get_pos(), 0, 0.5, 0)
					local dir
					local tpos = vector.copy(self._aom_aim_pos)
					tpos.y = tpos.y + 1
					if tpos then
						local tvel = self._aom_target:get_velocity()
						local dist = vector.distance(pos, tpos)
						tvel = vector.multiply(tvel, (dist / 20) * (math.random()/2 + 0.5))

						tpos = vector.add(tpos, tvel)

						local has_los = aom_entity_api.has_los_to_object(self, self._aom_target)
						local inaccuracy = (has_los and 1) or 6
						tpos = vector.offset(tpos,
							((math.random() - 0.5) * inaccuracy),
							((math.random() - 0.5) * inaccuracy),
							((math.random() - 0.5) * inaccuracy))
						if not has_los then
							tpos.y = tpos.y + math.random() * 6
						end

						dir = vector.direction(pos, tpos)
						dir.y = dir.y + 0.017 * (dist) + 0.05
					else break end

					local ent = aom_combat.projectile.add_projectile(self.object,
						"aom_animals:pipslug_spit_ENTITY",
						pos + (dir * 0.5), dir, 20
					)
					do_sound(self, "aom_animals_pipslug_".."spit", 1)
				until true end

			end,
		},
		death = {
			animation = "death",
			on_state_start = function(self)
				aom_entity_api.do_drops(self)
				self._aom_detectable = false
				self.object:set_properties({
					pointable = false,
				})
			end,
			step = function(self, dtime, moveresult)
				aom_entity_api.decelerate(self, 0.2)
				local vel = self.object:get_velocity()
				vel.y = vel.y - self._aom_gravity * dtime
				self.object:set_velocity(vel)
				if self._aom_state_time > 3 then
					self.object:remove()
				end
			end,
		},
	},
	_default_state = "idle",
	on_activate = function(self, staticdata, dtime_s)
		self.object:set_armor_groups({
			pierce=200,
			slash=100,
			blunt=200,
			magic=100,
			poison=100,
		})
		-- self.object:set_hp(self._aom_max_health)
		aom_entity_api.on_activate(self, staticdata, dtime_s)
		local pos = self.object:get_pos()
		if not pos then
			return self.object:remove()
		end
		if self._age ~= nil and (not self._no_despawn) and pos and not aom_entity_api.has_mobs_in_radius(pos, 60, {self.name}, 0, 5) then
			return self.object:remove()
		end
		if not self._aom_home_pos then
			self._aom_home_pos = pos
		end
	end,
	get_staticdata = function(self)
		return aom_entity_api.get_staticdata(self)
	end,
	on_deactivate = function(self, removal)
		return aom_entity_api.on_deactivate(self, removal)
	end,
	on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
		if damage and damage > 0 then
			do_sound(self, "aom_animals_pipslug_".."hurt", 1)
			if puncher and puncher ~= self.object and not self._aom_target then
				self._aom_target = puncher
				alert_nearby(self, 30)
			end
			local hp = self.object:get_hp() - damage
			if hp <= 0 then
				aom_entity_api.set_state(self, "death")
				self.object:set_hp(self._aom_max_health)
				self.object:set_armor_groups({fleshy=0})
				return true
			end
		end
		return aom_entity_api.damage.on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
	end,
	_aom_staticdata_load_list = {
		"_aom_speed",
		"_aom_damage_groups",
		"_aom_hostile",
	},
	_aom_speed = 4,
	_aom_acceleration = 20,
	_aom_gravity = 9,
	_aom_max_health = 10,
	_aom_hostile = {player=1},
	_aom_scariness = 5,
	_aom_home_pos = nil,
	_aom_damage_groups = {
		pierce=2,
		slash=1,
	},
	_animations = {
		idle		= {frames={x=10, y=29}, 				blend=0.1,	loop=true},
		move		= {frames={x=30, y=49},		speed=40,	blend=0.1,	loop=true},
		spit		= {frames={x=50, y=99},		speed=24,	blend=0.1,	loop=false},
		dig_in		= {frames={x=100, y=160}, 	speed=50,	blend=0.1,	loop=false},
		dig_idle	= {frames={x=160, y=169}, 	speed=40,	blend=0.1,	loop=false},
		dig_out		= {frames={x=170, y=199}, 	speed=34,	blend=0.1,	loop=false},
		death		= {frames={x=210, y=229},				blend=0.1,	loop=false},
	},
	_aom_wander = 3,
	_aom_range = 10,
	_aom_statusfx_enable = true,
	_mobcap_groups = {"hostile"},
	_aom_is_mob = true,
}


core.register_entity("aom_animals:pipslug", aom_animals.pipslug)


core.register_craftitem("aom_animals:pipslug_spawn",
{
	description = "Pipslug spawn egg",
	inventory_image = "aom_animals_pipslug.png",
	on_place = function(itemstack, placer, pointed_thing)
		local ent = core.add_entity(vector.offset(core.get_pointed_thing_position(pointed_thing), 0, 1, 0), "aom_animals:pipslug")
	end,
})
