local function rotate_and_shoot() end
local function draw_particles() end

local SENTRY_RANGE = 14



local multiplier2 = 3.6
local sentry = {
  initial_properties = {
    hp_max = 40, -- TODO: da aumentare una volta implementato lo scudo
    physical = true,
    collide_with_objects = true,
    visual = "mesh",
    mesh = "bl_sentrygun.b3d",
    backface_culling = false,
    visual_size = {x = 1 * multiplier2, y = 1 * multiplier2, z = 1 * multiplier2},
    textures = {"bl_sentrygun_texture.png"},
    collisionbox = {-0.15 * multiplier2, -0.141 * multiplier2, -0.14 * multiplier2, 0.15 * multiplier2, 0.16 * multiplier2, 0.14 * multiplier2}
    },

    _spawning = true,
    _shooting = false,
    _is_dying = false,

    on_activate = function(self)
      local sentry = self.object
      sentry:set_animation({x=120, y=130}, 20, nil, false)
      audio_lib.play_sound("bl_sentrygun_spawn", {gain = 0.2, pitch = 1.15, object = sentry, max_hear_distance = SENTRY_RANGE + 5})
      core.after(1.2, function()
        if not self.object then return end
        self.object:set_animation({x=1, y=100}, 20)
        self._spawning = false
      end)
    end,

    on_step = function(self, dtime, moveresult)
      if self._spawning or self._shooting then return end

      local obj
      local turret = self.object
      local t_pos = turret:get_pos()
      local dir = vector.new(math.sin(turret:get_yaw()), 0, math.cos(turret:get_yaw()))
      local to_target_dir, angle

      -- cerca l'obiettivo
      for _, objs in pairs(core.get_objects_inside_radius(t_pos, SENTRY_RANGE)) do
        to_target_dir = vector.direction(t_pos, vector.add(objs:get_pos(), vector.new(0,1,0)))
        angle = math.acos(vector.dot(vector.normalize(dir), to_target_dir))
        if objs:is_player() and angle <= math.pi/3 then
          obj = objs
          break
        end
      end

      if not obj then return end

      turret:set_animation({x=105, y=106}, 10)
      self._shooting = true
      rotate_and_shoot(turret, to_target_dir)   -- 1° colpo

      core.after(0.3, function()            -- 2° colpo
        -- se controllo solo obj e l'obiettivo si è sconnesso, passa il controllo
        if not obj:get_pos() or not self.object or self._is_dying then return end
        to_target_dir = vector.direction(t_pos, vector.add(obj:get_pos(), vector.new(0,1,0)))
        rotate_and_shoot(turret, to_target_dir)

        core.after(0.3, function()          -- 3° colpo
          if not obj:get_pos() or not self.object or self._is_dying then return end
          to_target_dir = vector.direction(t_pos, vector.add(obj:get_pos(), vector.new(0,1,0)))
          rotate_and_shoot(turret, to_target_dir)
        end)
      end)

      core.after(1, function()
        if not self.object then return end
        self.object:set_animation({x=26, y=26})

        core.after(1, function()
          if not self then return end
          turret:set_bone_override("Rotation", {position = vector.new(0,1,0), rotation = vector.zero()})
          turret:set_animation({x=1, y=100}, 20)
          self._shooting = false
        end)
      end)
    end,

    on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
      local entity = self.object
      if not self._is_dying and entity:get_hp() - damage <= 0 then
        entity:set_hp(1)
        entity:set_animation({x=112, y=115}, 25, nil, false)
        self._is_dying = true

        audio_lib.play_sound("bl_sentrygun_death", {pos = entity:get_pos(), max_hear_distance = SENTRY_RANGE + 5})
        core.add_particlespawner({
          attached = self.object,
          amount = 200,
          time = 0.1,
          minvel = {x = -10,y = -6, z = -10},
          maxvel = {x = 10, y = 6, z = 10},
          minsize = 1,
          maxsize = 3,
          texture = {
            name = "bl_sentrygun_explosion.png",
            alpha_tween = {1, 0},
            scale_tween = {
              {x = 1, y = 1},
              {x = 0, y = 0},
            },
            animation = {
              type = "vertical_frames",
              aspect_w = 16, aspect_h = 16,
              length = 0.3,
            },
            },
          glow = 12,
        })

        core.after(0.15, function()
          entity:punch(puncher, nil, {damage_groups = { fleshy = 999}})
        end)

        return true
      end
    end,

    on_death = function(self, killer)
      local p_name = killer:get_player_name()
      if not arena_lib.is_player_in_arena(p_name) then return end

      bl_tutorial.decrease_sentries(p_name)
    end,
}

core.register_entity("bl_tutorial:sentry", sentry)



function rotate_and_shoot(sentry, dir)
  if not sentry:get_rotation() then return end -- se controllo solo `sentry`, crasha sotto. Prob le entità non vengono rimosse all'istante, ma le loro funzioni sì (?)

  local sentry_rot_y = sentry:get_rotation().y -- between 0 and 2pi
  local pitch = vector.dir_to_rotation(dir).x
  local yaw = vector.dir_to_rotation(dir).y

  -- convert the turret yaw rotation to range [-pi, pi] for proper comparison
  if sentry_rot_y > math.pi then
    sentry_rot_y = sentry_rot_y - 2 * math.pi
  end

  -- calculate the normalized yaw angle difference in the range [-pi, pi]
  local yaw_nrml = yaw - sentry_rot_y

  if yaw_nrml > math.pi then
    yaw_nrml = yaw_nrml - 2 * math.pi
  elseif yaw_nrml < -math.pi then
    yaw_nrml = yaw_nrml + 2 * math.pi
  end

  -- invert the yaw for the correct rotation direction
  yaw_nrml = -yaw_nrml

  local new_rot = vector.new(pitch, yaw_nrml, 0)

  sentry:set_bone_override("Rotation", {
    position = {
      vec = vector.new(0, 1, 0),
      absolute = true
    },
    rotation = {vec = new_rot, absolute=true, interpolation = 0.1}
  })

  local sentry_centre = 0.3
  local pointed_object = weapons_lib.get_pointed_objects(sentry, 20, false, {height = sentry_centre, dir = dir})

  draw_particles(dir, vector.add(sentry:get_pos(), vector.new(0, sentry_centre, 0)))
  audio_lib.play_sound("bl_sentrygun_shoot", {pitch =  2.3, object = sentry, max_hear_distance = SENTRY_RANGE + 5})

  if next(pointed_object) then
    local target = pointed_object[1].object

    if target:get_hp() < 6 then
      if arena_lib.is_player_in_arena(target:get_player_name()) then
        bl_tutorial.kill(target)
      else
        target:set_hp(2)
      end

    else
      target:punch(sentry, nil, {damage_groups = {fleshy = 5}})
    end
  end
end



function draw_particles(dir, origin)
  core.add_particlespawner({
    amount = 5,
    time = 0.1,
    pos = vector.new(origin),
    vel = vector.multiply(dir, 60),
    size = 1.5,
    collisiondetection = true,
    collision_removal = true,
    object_collision = true,
    texture = "bl_pixelgun_trail.png"
  })
end