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



local function alert_nearby_deer(self, dist)
    if not dist then dist = 30 end
    local nearby_objects = minetest.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:deer" then
            aom_entity_api.set_state(ent, "flee")
            ent._aom_target = self._aom_target
        end
    end
end


local deer = {
    initial_properties = {
        visual = "mesh",
        mesh = "aom_deer.b3d",
        textures = {"aom_deer.png"},
        use_texture_alpha = false,
        stepheight = 0.5,
        hp_max = 20,
        physical = true,
        collisionbox = {-0.4, -0.5, -0.4, 1.5, 1, 0.4},
        selectionbox = {-0.4, -0.5, -0.4, 1.5, 1, 0.4},
        pointable = true,
        damage_texture_modifier = "^[colorize:#ff9999:50",
        static_save = false,
    },
    _name = "aom_animals:deer",

    on_step = function(self, dtime, moveresult)
        aom_entity_api.mob_on_step(self, dtime, moveresult)
    end,
    _drop = {
        max_items = 2,
        items = {
            {
                rarity = 1,
                items = {"aom_animals:animal_meat"},
            },
            {
                rarity = 2,
                items = {"aom_animals:animal_meat"},
            },
        }
    },
    on_death = function(self, killer)
        -- if killer then
        -- end
    end,

    _get_deer_pack = function(self)
        self._aom_deer_pack = aom_entity_api.get_objects_of_type(self.object:get_pos(), 20, {["aom_animals:deer"]=true})
    end,

    _states = {
        on_step = function(self, dtime, moveresult)
            aom_entity_api.test_fall_damage(self, dtime, false)
            if not self.object:get_pos() then
                return "die"
            end

            if self._aom_deer_pack_recalc_timer and self._aom_deer_pack_recalc_timer > 0 then
                self._aom_deer_pack_recalc_timer = self._aom_deer_pack_recalc_timer - dtime
            else
                self._aom_deer_pack_recalc_timer = math.random() + 1
                self:_get_deer_pack()
            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)
                self.object:set_velocity(vector.new(0,0,0))
                self._aom_speed = 4
            end,
            step = function(self, dtime, moveresult)
                aom_entity_api.decelerate(self, 0.5)
                aom_entity_api.get_wander(self, 270)
                aom_entity_api.get_target(self, nil, {no_to_pos=false})

                local dist = aom_entity_api.get_target_dist(self)

                if self._aom_to_pos and self._aom_state_time > 5 then
                    return "roam"
                elseif self._aom_to_pos and self._aom_target and ((math.random() < 0.01)
                or (dist and dist < 10)) then
                    return "flee"
                end
            end,
        },
        roam = {
            -- animation = "walk",
            on_state_start = function(self)
                self._aom_roam_check_timer = 4
                self._aom_speed = 4
            end,
            step = function(self, dtime, moveresult)
                self._aom_roam_check_timer = self._aom_roam_check_timer - dtime

                aom_entity_api.get_wander(self, 300)

                local tmp_vel = self.object:get_velocity()
                tmp_vel.y = 0
                if vector.length(tmp_vel) > 0.2 then
                    aom_entity_api.set_my_animation(self, "walk")
                else
                    aom_entity_api.set_my_animation(self, "idle")
                end

                aom_entity_api.get_target(self, nil, {no_to_pos=false})
                aom_entity_api.get_path(self)
                aom_entity_api.do_path(self)
                aom_entity_api.check_jump(self, 4)

                if not aom_entity_api.path_reachable(self) then
                    self._aom_to_pos = nil
                end
                -- no target or target pos
                if (not self._aom_to_pos) and (not self._aom_target) then
                    return "idle"
                end

                -- found target, so run
                if self._aom_target then
                    return "flee"
                end

                if self._aom_roam_check_timer <= 0 and self._aom_to_pos
                and (self._aom_deer_pack and #self._aom_deer_pack > 1) then
                    self._aom_roam_check_timer = 3
                    local list = self._aom_deer_pack
                    local avg_pos

                    for i, obj in pairs(list) do
                        if obj then
                            local opos = obj:get_pos()
                            if opos then
                                if avg_pos then
                                    avg_pos = vector.add(avg_pos, opos)
                                else
                                    avg_pos = opos
                                end
                            end
                        end
                    end
                    avg_pos = vector.divide(avg_pos, #list)
                    avg_pos = vector.add(avg_pos, self._aom_to_pos)
                    avg_pos = vector.divide(avg_pos, 2)

                    self._aom_to_pos = vector.copy(avg_pos)
                    self._aom_path = {}
                    self._aom_path_timer = 30947
                    aom_entity_api.get_path(self, aom_entity_api.min_cost)
                    -- minetest.chat_send_all("corrected to pack " .. dump(self._aom_path ~= nil))
                end

                aom_entity_api.rotate_to_path(self, dtime*8)
            end,
        },
        flee = {
            animation = nil,
            on_state_start = function(self)
                -- self._aom_to_pos = nil
                self._aom_speed = 8
            end,
            step = function(self, dtime, moveresult)

                local tmp_vel = self.object:get_velocity()
                tmp_vel.y = 0
                if vector.length(tmp_vel) > 4 then
                    aom_entity_api.set_my_animation(self, "run")
                elseif vector.length(tmp_vel) > 0.2 then
                    aom_entity_api.set_my_animation(self, "walk")
                else
                    aom_entity_api.set_my_animation(self, "idle")
                end

                local dist = aom_entity_api.get_target_dist(self)
                if dist and dist > 90 then return "roam" end

                if not self._aom_target and self._aom_state_time > 5 then
                    return "roam"
                elseif self._aom_target then
                    self._aom_run_from_pos = self._aom_target:get_pos()
                end

                if self._aom_run_from_pos then
                    aom_entity_api.run_from(self, self._aom_run_from_pos, {})
                end

                if (not self._aom_to_pos) and not self._aom_time_before_idle then
                    self._aom_time_before_idle = self._aom_state_time
                    if self._aom_state_time > self._aom_time_before_idle + 1 then
                        return "idle"
                    end
                end

                aom_entity_api.check_jump(self, 4)

                aom_entity_api.rotate_to_path(self, dtime*8)
            end,
        },
        death = {
            animation = "death",
            on_state_start = function(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 > 2 then
                    aom_entity_api.do_drops(self)
                    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=100,
            magic=100,
            poison=100,
        })
        -- self.object:set_hp(self._aom_max_health)
        aom_entity_api.on_activate(self, staticdata, dtime_s)
        self._aom_deer_pack_recalc_timer = 0

        local pos = self.object:get_pos()
        if self._age ~= nil and (not self._no_despawn) and pos and not aom_entity_api.has_mobs_in_radius(pos, 40, {self.name}, 0, 5) then
            return self.object:remove()
        end
    end,
    get_staticdata = function(self)
        return aom_entity_api.get_staticdata(self)
    end,
    on_deactivate = function(self, removal)
        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
            aom_animals.do_sound(self, "hurt_0", 1)
            if puncher and puncher ~= self.object and not self._aom_target then
                self._aom_target = puncher
                alert_nearby_deer(self, 80)
                aom_entity_api.set_state(self, "flee")
            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 = 2,
    _aom_acceleration = 20,
    _aom_gravity = 9,
    _aom_max_health = 20,
    _aom_deer_pack = {},
    _aom_deer_pack_recalc_timer = 0,
    _aom_hostile = {player=1, ["aom_animals:wolf"]=1},
    _aom_scariness = 1,
    _aom_damage_groups = {
        pierce=1,
        slash=1,
        blunt=2,
    },
    _animations = {
      idle = {frames={x=0, y=43}, blend=0.2, speed=40},
      walk = {frames={x=60, y=98}, blend=0.1, speed=40},
      run = {frames={x=109, y=128}, blend=0.1, speed=25},
      death = {frames={x=149, y=166}, blend=0.2, loop=false, speed=25},
      eat = {frames={x=194, y=223}, blend=0.4, speed=25}, --unused currently
      head_turn = {frames={x=264, y=313}, blend=0.2, loop=false, speed=25}, --unused currently
    },
    _aom_wander = 3,
    _aom_range = 50,
    _aom_statusfx_enable = true,
}


minetest.register_entity("aom_animals:deer", deer)


minetest.register_craftitem("aom_animals:deer_spawn",
{
    description = "Deer spawn egg",
    inventory_image = "aom_deer.png",
    on_place = function(itemstack, placer, pointed_thing)
        local ent = minetest.add_entity(vector.offset(minetest.get_pointed_thing_position(pointed_thing), 0, 1, 0), "aom_animals:deer")
    end,
})




local _biomes = { ["ash_forest_dense"]=0.8, ["ash_forest"]=0.5, ["taiga_tall_dense"]=1, ["ruined_valley"]=0.3, }
local _nodes = { ["aom_soil:forest_dirt"]=0.5, ["aom_soil:forest_grass_1"]=0.2, ["aom_soil:forest_grass_2"]=1, ["aom_soil:snow"]=1, }

if aom_mob_spawn then
    aom_mob_spawn.register_mob({
        name = "aom_animals:deer",
        groups = {"passive", "nature", "aom_animals_deer"},
        biomes = {},
        on_spawn = function(self, pos)
            for i = 0, (math.random(1,3)) do
                local spos = vector.offset(
                    pos,
                    math.random()*2-1,
                    0.8,
                    math.random()*2-1
                )
                local obj = minetest.add_entity(spos, "aom_animals:deer")
                obj:set_yaw(math.random() * math.pi * 2)
            end
        end,
        can_spawn = function(pos, spawn_info)
            -- do cheap tests first
            if not aom_dimensions.is_in("overworld", pos) then return false end
            if not aom_mob_spawn.has_head_room(pos, 1) then return false end
            local node_below = minetest.get_node(vector.offset(
                pos, 0, -1, 0
            ))
            -- only spawn under sky
            if not aom_mob_spawn.has_natural_light(pos, 9, 15) then return false end
            -- don't spawn if artificial lights around
            if aom_mob_spawn.has_light(pos, 2, 15, 0) then return false end

            local spawnable = false
            if (_biomes[spawn_info.biome_name] ~= nil) and (math.random() < _biomes[spawn_info.biome_name]) then
                spawnable = true
            elseif (_nodes[node_below.name] ~= nil) and (math.random() < _nodes[node_below.name]) then
                spawnable = true
            end

            -- do expensive tests last
            if spawnable then
                if aom_entity_api.has_mobs_in_radius(pos, 60, {"aom_animals:deer"}, 0, 1) then
                    return true
                end
            end
            return false
        end,
        can_despawn = function(self)
            local pos = self.object:get_pos()
            if (not pos) or not aom_entity_api.has_mobs_in_radius(pos, 50, {"aom_animals:deer"}, 0, 7) then
                return true
            end
            if self._age and self._age < 120 then return false end
            return true
        end,
    })
    aom_mob_spawn.cap.aom_animals_deer.max = 12
end


deer = nil
