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

-- local parts = {}
local function particles(self)
    -- local i = #parts+1
    -- parts[i] = {}
    self._particles = {}

    self._particles[#self._particles+1] = minetest.add_particlespawner({
        amount = 20,
        time = 0,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        attached = self.object, -- to object ref
        vertical = false, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_smoke.png",
        glow = 2,
        minpos = vector.new(-0.2, -0.2, -1),
        maxpos = vector.new(0.2, 0.2, -2),
        minvel = vector.new(-0.2, -0.2, -1),
        maxvel = vector.new(0.2, 0.2, -2),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 2,
        maxexptime = 4,
        minsize = 2,
        maxsize = 8,
    })

    self._particles[#self._particles+1] = minetest.add_particlespawner({
        amount = 10,
        time = 0,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        attached = self.object, -- to object ref
        vertical = false, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_spark.png",
        glow = 8,
        minpos = vector.new(-0.2, -0.2, -2),
        maxpos = vector.new(0.2, 0.2, -3),
        minvel = vector.new(-2, -2, 0),
        maxvel = vector.new(2, 2, -8),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 0.5,
        maxexptime = 1,
        minsize = 2,
        maxsize = 3,
    })

    self._particles[#self._particles+1] = minetest.add_particlespawner({
        amount = 20,
        time = 0,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        attached = self.object, -- to object ref
        vertical = false, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_flame.png",
        glow = 2,
        minpos = vector.new(-0.2, -0.2, -2),
        maxpos = vector.new(0.2, 0.2, -2),
        minvel = vector.new(-0.5, -0.5, 0),
        maxvel = vector.new(0.5, 0.5, -8),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 0.5,
        maxexptime = 1,
        minsize = 2,
        maxsize = 6,
    })
end

local function euler_to_direction(v)
    return vector.new(
        -math.sin(v.y) * math.cos(v.x),
        math.sin(v.x),
        math.cos(v.y) * math.cos(v.x)
    )
end

local function delete_particles(self)
    for i, id in pairs(self._particles or {}) do
        minetest.delete_particlespawner(id)
    end
end

local function explode(self, no_sound)
    if (not self) or self._exploded then return end
    self._exploded = true

    local p = self.object:get_pos()
    if not p then return end
    pmb_combat.explosions.explode(p, {
        radius = 4,
        owner = self.object,
        no_drops = false,
        damage_range_factor = 3,
        damage_groups = {
            fleshy = 25,
            sharp = 15,
            blunt = 15,
        }
    })
    delete_particles(self)
    if not no_sound then
        minetest.sound_play("gm_windmills_rocket_explode", {
            gain = 1,
            pos = p,
            max_hear_distance = 100,
        })
    end
    if self._sound_burn then
        minetest.sound_stop(self._sound_burn)
    end
    minetest.add_particlespawner({
        amount = 30,
        time = 0.01,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        -- attached = self.object, -- to object ref
        vertical = false, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_smoke.png",
        glow = 2,
        minpos = vector.new(p.x - 2, p.y - 2, p.z - 2),
        maxpos = vector.new(p.x + 2, p.y + 2, p.z + 2),
        minvel = vector.new(-1, -1, 1),
        maxvel = vector.new(1, 1, 1),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 0.5,
        maxexptime = 2,
        minsize = 8,
        maxsize = 20,
    })
    minetest.add_particlespawner({
        amount = 30,
        time = 0.01,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        -- attached = self.object, -- to object ref
        vertical = false, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_spark.png",
        glow = 8,
        minpos = vector.new(p.x - 1, p.y - 1, p.z - 1),
        maxpos = vector.new(p.x + 1, p.y + 1, p.z + 1),
        minvel = vector.new(-6, -6, -6),
        maxvel = vector.new( 6,  6,  6),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 0.5,
        maxexptime = 1,
        minsize = 2,
        maxsize = 4,
    })
    minetest.add_particlespawner({
        amount = 30,
        time = 0.01,
        collisiondetection = false,
        collision_removal = false,
        object_collision = false,
        -- attached = self.object, -- to object ref
        vertical = true, -- If true face player using y axis only:-- If true face player using y axis only:
        texture = "gm_windmills_rocket_flame.png",
        glow = 5,
        minpos = vector.new(p.x - 1, p.y - 1, p.z - 1),
        maxpos = vector.new(p.x + 1, p.y + 1, p.z + 1),
        minvel = vector.new(-2, -2, -2),
        maxvel = vector.new( 2,  2,  2),
        minacc = {x=0, y=0, z=0},
        maxacc = {x=0, y=0, z=0},
        minexptime = 1,
        maxexptime = 2,
        minsize = 2,
        maxsize = 4,
    })
    self.object:remove()
end

local function drill_forward(self)
    local p = self.object:get_pos()
    local forward = self.object:get_rotation()
    forward = euler_to_direction(forward)

    local v = vector.multiply(forward, 2)
    -- keep track
    self._forward_pos = p

    self.object:set_velocity(v)

    -- try to break stuff
    local node_ahead = minetest.get_node(self._forward_pos)
    local ndef = minetest.registered_nodes[node_ahead.name]
    if node_ahead.name ~= "pmb_util:barrier" and ndef and ndef.walkable then
        explode(self)
        return true
    end
end

-- /spawnentity gm_windmills:rockethead_ENTITY
local csize = 1.0
minetest.register_entity("gm_windmills:rockethead_ENTITY", {
    initial_properties = {
        visual = "mesh",
        mesh = "gm_windmills_rocket.b3d",
        backface_culling = true,
        textures = {
            "gm_windmills_rocket.png",
            "gm_windmills_rocket.png",
        },
        stepheight = 0,
        hp_max = 1,
        physical = false,
        collisionbox = {
            -csize, -csize, -csize, csize, csize, csize,
        },
    },
    glow = 2,
    _get_target = function(self)
        local closestobj
        local closestdist = 110
        local pos = self.object:get_pos()
        local near = minetest.get_objects_inside_radius(pos, 100)
        for i, obj in ipairs(near) do
            local ent = obj:get_luaentity()
            if ent and ent._name == "gm_windmills:windmill_head_ENTITY" then
                local dist = vector.distance(pos, obj:get_pos())
                if dist < closestdist then
                    closestobj = obj
                    closestdist = dist
                end
            end
        end
        if closestobj then
            self._pmb_target = closestobj
            return true
        end
    end,
    _update_sounds = function(self)
        if self._sound_burn then minetest.sound_stop(self._sound_burn) end
        self._sound_burn = minetest.sound_play("gm_windmills_rocket_fire", {
            gain = 0.3,
            object = self.object,
            max_hear_distance = 70,
        })
    end,
    _sound_timer = 4,
    on_step = function(self, dtime)
        self._sound_timer = self._sound_timer - dtime

        if not self._init then
            self._init = true
            -- self.object:set_animation({x=0,y=79}, 24, 0.3, true)

            self._sound_burn = minetest.sound_play("gm_windmills_rocket_fire", {
                gain = 1,
                object = self.object,
                max_hear_distance = 30,
                loop = true,
            })

            self._inaccurate = (math.random() < 0.5) or nil

            if not self._pmb_target and self:_get_target() then
                pmb_entity_api.rotate_to_target(self, -0.9, true)

                self._to_pos = vector.offset(
                    self._pmb_target:get_pos(),
                    (math.random() * 2 - 1) * 10,
                    (math.random() * 2 - 1) * 10,
                    (math.random() * 2 - 1) * 10
                )
            end
        end

        if self._sound_timer <= 0 then
            self._sound_timer = 4
            self._update_sounds(self)
        end

        if self._pmb_target then
            if not self._inaccurate then
                pmb_entity_api.rotate_to_target(self, 0.005 * math.random(10), true)
            else
                pmb_entity_api.rotate_to_pos(self, self._to_pos, 0.005 * math.random(10), true)
                if vector.distance(self.object:get_pos(), self._to_pos) < 1 then
                    self._inaccurate = nil
                    self._to_pos = nil
                end
            end
            if drill_forward(self) then return end
        end
        if not self:_get_target() then
            explode(self, true)
        end
    end,
    on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, direction, damage)
        if minetest.is_player(puncher) then
            minetest.after(0.1, function()
                explode(self)
            end)
        end
    end,
    on_deactivate = function(self, removal)
        if removal then
            explode(self)
        end
    end,
    on_activate = function(self, staticdata, dtime_s)

        if gm_windmills.gamestate ~= "active" then
            explode(self, true)
            return
        end

        local data = minetest.deserialize(staticdata)
        if data then
            for key, val in pairs(data) do
                self[key] = val
            end
            if data._rotation then
                self.object:set_rotation(data._rotation)
            end
        end

        local pos = self.object:get_pos()
        local d = vector.distance(gm_windmills.game_origin, pos)
        if d > 160 then
            explode(self, true)
            return
        end

        self.object:set_armor_groups({
            projectile = 1000
        })

        particles(self)
    end,
    get_staticdata = function(self)
        if self._sound_burn then minetest.sound_stop(self._sound_burn) end
        -- delete_particles(self)
        local data = {}
        for i, key in pairs(self._pmb_staticdata_load_list) do
            if key and self[key] ~= nil then
                data[key] = self[key]
            end
        end

        return minetest.serialize(data)
    end,
    _pmb_staticdata_load_list = {
        "_rotation",
    },
})

