local S = core.get_translator("bl_tutorial")

local function phase1() end
local function phase2() end
local function phase3() end
local function phase4() end
local function phase5() end
local function phase6() end
local function anchor_player() end
local function remove_entities() end
local function spawn_sentries4() end
local function spawn_sentries5() end

local tracker = {}                   -- KEY = p_name; VALUE = phases
local phases = {
  [1] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = true },     -- intro
  [2] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = true,  run = function(player) phase2(player) end },     -- propulsor
  [3] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = false, run = function(player) phase3(player) end },     -- obstacles
  [4] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = false, run = function(player) phase4(player) end },     -- side dash & skill
  [5] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = false, run = function(player) phase5(player) end },     -- ball
  [6] = { start_coords = {}, end_coords = {}, prerequisites_satisfied = true,  run = function(player) phase6(player) end },     -- rays
  current_phase = 1,
  propulsor_hint = nil,
  obstacles_left = 5,
  sentries_left = 4,
  completed = false
}



core.register_globalstep(function(dtime)
  for pl_name, data in pairs(tracker) do
    local player = core.get_player_by_name(pl_name)
    local p_pos = player:get_pos()
    local phase = tracker[pl_name][data.current_phase]
    local end_coords = phase.end_coords

    if math.abs(p_pos.x - end_coords.x) <= 1.8 and math.abs(p_pos.z - end_coords.z) <= 1.8 and
       p_pos.y >= end_coords.y - 1 and p_pos.y <= end_coords.y + 1 and phase.prerequisites_satisfied then
      local next_phase = tracker[pl_name][data.current_phase + 1]
      local arena = arena_lib.get_arena_by_player(pl_name)

      player:set_pos(next_phase.start_coords)
      player:set_hp(999)
      arena.players[pl_name].stamina = 99 -- così aggiorna l'HUD dato che non è  a 100 ;)))

      data.current_phase = data.current_phase + 1
      anchor_player(player)
      bl_tutorial.hud_show(player)
      next_phase.run(player)
    end
  end
end)



function bl_tutorial.initialise(arena, p_name)
  panel_lib.get_panel(p_name, "bl_keys"):hide()
  panel_lib.get_panel(p_name, "bl_scoreboard"):hide()
  panel_lib.get_panel(p_name, "bl_skill"):hide()
  panel_lib.get_panel(p_name, "bl_stamina"):hide()
  panel_lib.get_panel(p_name, "bl_weapons"):hide()
  bl_tutorial.hud_add(p_name)

  arena.initial_time = 900

  local start_coords1 = arena.spawn_points[1].pos
  local start_coords2 = vector.add(start_coords1, vector.new(0, 0, -56))
  local start_coords3 = vector.add(start_coords1, vector.new(-50, 0, 0))
  local start_coords4 = vector.add(start_coords3, vector.new(0, 0, -56))
  local start_coords5 = vector.add(start_coords4, vector.new(-58, 0, 0))
  local start_coords6 = vector.add(start_coords5, vector.new(0, 0, 49))
  local end_coords1 = vector.add(start_coords1, vector.new(0, 4, -32))
  local end_coords2 = vector.add(start_coords2, vector.new(0, 8, -9))
  local end_coords3 = vector.add(end_coords1, vector.new(-50, 0, 0))
  local end_coords4 = vector.add(start_coords4, vector.new(0, 0, -23))
  local end_coords5 = vector.add(start_coords5, vector.new(0, 0, -23))
  local end_coords6 = vector.new(0,-999999,0) -- giusto per evitare un crash sui controlli del globalstep

  tracker[p_name] = table.copy(phases)
  local p_tracker = tracker[p_name]

  p_tracker[1].end_coords = end_coords1
  p_tracker[2].start_coords = start_coords2
  p_tracker[2].end_coords = end_coords2
  p_tracker[3].start_coords = start_coords3
  p_tracker[3].end_coords = end_coords3
  p_tracker[4].start_coords = start_coords4
  p_tracker[4].end_coords = end_coords4
  p_tracker[5].start_coords = start_coords5
  p_tracker[5].end_coords = end_coords5
  p_tracker[6].start_coords = start_coords6
  p_tracker[6].end_coords = end_coords6

  local player = core.get_player_by_name(p_name)

  -- rimuovo l'SMG (che ha creato l'HUD), così da aver la mano libera
  player:get_inventory():set_stack("main", 1, {})
  phase1(player)
end





----------------------------------------------
-------------------FASE 1---------------------
----------------------------------------------

function phase1(player)
  anchor_player(player)
  bl_tutorial.hud_show(player)

  player:hud_set_hotbar_image("bl_tutorial_gui_hotbar.png")
  player:hud_set_hotbar_itemcount(1)
  player:hud_set_flags({hotbar = false})

  local p_name = player:get_player_name()

  arena_lib.HUD_send_msg("title", p_name, S("Welcome to Block League! Take a deep breath, and take a look around"))

  core.after(6.5, function()
    if not tracker[p_name] then return end
    arena_lib.HUD_send_msg("title", p_name, S("Let's just go for a walk"), 4)

    core.after(4, function()
      if not tracker[p_name] then return end
      arena_lib.HUD_send_msg("broadcast", p_name, S("Reach the end of the hallway"))
      player:get_attach():remove()
    end)
  end)
end





----------------------------------------------
-------------------FASE 2---------------------
----------------------------------------------

function phase2(player)
  local p_name = player:get_player_name()
  local i_pos = vector.add(tracker[p_name][2].start_coords, vector.new(0, 4.5, -20))

  remove_entities(i_pos, 3, "__builtin:item")
  remove_entities(i_pos, 3, "bl_tutorial:propulsor_hint")

  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("Do you see that platform up high? There is no way you can reach it without a propulsor"), 7.5)

  core.after(7.5, function()
    if not tracker[p_name] then return end
    arena_lib.HUD_send_msg("broadcast", p_name, S("Grab the propulsor at the end of the steps"))

    core.add_item(i_pos, ItemStack("block_league:propulsor"))
    player:get_attach():remove()
  end)
end



-- raccolta propulsore
core.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch,  ...)
  if itemstack:get_name() == "block_league:propulsor" and core.is_player(picker) and arena_lib.is_player_in_arena(picker:get_player_name(), "block_league") then
    local p_name = picker:get_player_name()

    picker:hud_set_flags({hotbar = true})
    panel_lib.get_panel(p_name, "bl_stamina"):show()
    arena_lib.HUD_hide("broadcast", p_name)
    arena_lib.HUD_send_msg("title", p_name, S("Now reach the platform!"), 3.5)

    local p_tracker = tracker[p_name]
    local e_pos = vector.add(pointed_thing.ref:get_pos(), vector.new(0, 0.7, 1.75))

    core.after(3, function()
      if not p_tracker or p_tracker.current_phase ~= 2 then return end
      p_tracker.propulsor_hint = core.add_entity(e_pos, "bl_tutorial:propulsor_hint")
      arena_lib.HUD_send_msg("broadcast", p_name, S("LMB on a surface to bounce (consumes stamina, yellow bar)"))
    end)
  end
end)





----------------------------------------------
-------------------FASE 3---------------------
----------------------------------------------

function phase3(player)
  local p_name = player:get_player_name()
  local p_tracker = tracker[p_name]
  local start_coords = p_tracker[3].start_coords
  local e_pos1 = vector.add(start_coords, vector.new(0, 1.7, -9.5))
  local e_pos2 = vector.add(e_pos1, vector.new(0, 0, -5.025))
  local e_pos3 = vector.add(e_pos2, vector.new(0, 1, -5.025))
  local e_pos4 = vector.add(e_pos3, vector.new(0, 1.5, -5.025))
  local e_pos5 = vector.add(e_pos4, vector.new(0, 1, -5.025))

  if p_tracker.propulshor_hint then p_tracker.propulsor_hint:remove() end
  remove_entities(start_coords, 60, "bl_tutorial:obstacle")

  core.add_entity(e_pos1, "bl_tutorial:obstacle")
  core.add_entity(e_pos2, "bl_tutorial:obstacle")
  core.add_entity(e_pos3, "bl_tutorial:obstacle")
  core.add_entity(e_pos4, "bl_tutorial:obstacle")
  core.add_entity(e_pos5, "bl_tutorial:obstacle")

  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("And now for the cool part: shooting!"))

  core.after(4, function()
    if not tracker[p_name] then return end
    arena_lib.HUD_send_msg("title", p_name, S("Here's a weapon: have fun with the obstacles in front of you"), 5)

    core.after(6, function()
      if not tracker[p_name] then return end
      player:hud_set_hotbar_image("arenalib_gui_hotbar2.png")
      player:hud_set_hotbar_itemcount(2)

      local inv = core.get_player_by_name(p_name):get_inventory()
      local smg = "block_league:smg"
      local arena = arena_lib.get_arena_by_player(p_name)

      inv:set_stack("main", 1, ItemStack(smg))
      inv:set_stack("main", 2, ItemStack("block_league:propulsor"))

      arena.weapons_disabled = false
      panel_lib.get_panel(p_name, "bl_weapons"):show()
      block_league.HUD_weapons_update(arena, p_name, smg)

      arena_lib.HUD_send_msg("broadcast", p_name, S("LMB/RMB: shoot, Q: reload | Obstacles left: @1", 5))
      player:get_attach():remove()
    end)
  end)
end



function bl_tutorial.decrease_obstacles(p_name)
  tracker[p_name].obstacles_left = tracker[p_name].obstacles_left - 1

  local obstacles_left = tracker[p_name].obstacles_left

  arena_lib.HUD_send_msg("broadcast", p_name, S("LMB/RMB: shoot, Q: reload | Obstacles left: @1", obstacles_left))

  if obstacles_left == 0 then
    arena_lib.HUD_hide("broadcast", p_name)
    arena_lib.HUD_send_msg("title", p_name, S("Excellent! And have you noticed that left click and right click shoot differently?"), 5)

    core.after(5, function()
      if not tracker[p_name] then return end
      arena_lib.HUD_send_msg("broadcast", p_name, S("Reach the end of the hallway"))
      tracker[p_name][3].prerequisites_satisfied = true
    end)
  end
end





----------------------------------------------
-------------------FASE 4---------------------
----------------------------------------------

function phase4(player)
  local p_name = player:get_player_name()
  local start_coords = tracker[p_name][4].start_coords
  local e_pos1 = vector.add(start_coords, vector.new(0, 0, -10))

  remove_entities(e_pos1, 30, "bl_tutorial:sentry")

  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("Beware! An enemy is appearing!"))

  core.after(4, function()
    if not tracker[p_name] then return end
    arena_lib.HUD_send_msg("title", p_name, S("Take cover with the propulsor (right click) and then eliminate it from a safe place"), 6)

    core.after(6, function()
      if not tracker[p_name] then return end
      arena_lib.HUD_send_msg("broadcast", p_name, S("Sentry guns left: @1", "1?"))
      core.add_entity(e_pos1, "bl_tutorial:sentry")
      player:get_attach():remove()
    end)
  end)
end



function bl_tutorial.decrease_sentries(p_name)
  tracker[p_name].sentries_left = tracker[p_name].sentries_left - 1

  local sentries_left = tracker[p_name].sentries_left

  -- per la 5° fase, dove non serve ammazzarle
  if sentries_left < 0 then
    return

  -- uccidendo la prima, si dà vita alle altre
  elseif sentries_left == 3 then
    arena_lib.HUD_send_msg("title", p_name, S("Oh no, they're increasing!"), 2)

    core.after(2, function()
      if not tracker[p_name] then return end

      local start_coords = tracker[p_name][4].start_coords
      spawn_sentries4(start_coords)
      arena_lib.HUD_send_msg("broadcast", p_name, S("Sentry guns left: @1", sentries_left))
    end)

  else
    arena_lib.HUD_send_msg("broadcast", p_name, S("Sentry guns left: @1", sentries_left))

    if sentries_left == 0 then
      arena_lib.HUD_send_msg("broadcast", p_name, S("Reach the next section"))
      tracker[p_name].sentries_left = -1
      tracker[p_name][4].prerequisites_satisfied = true
    end
  end
end



function bl_tutorial.kill(player)
  local p_name = player:get_player_name()
  local p_tracker = tracker[p_name]
  local curr_phase = tracker[p_name].current_phase
  local start_coords = tracker[p_name][curr_phase].start_coords
  local arena = arena_lib.get_arena_by_player(p_name)
  local smg = "block_league:smg"

  player:set_hp(999)
  player:set_pos(start_coords)
  arena.players[p_name].stamina = 99
  weapons_lib.refill(p_name, player:get_inventory():get_stack("main", 1))

  block_league.HUD_weapons_update(arena, p_name, smg)
  bl_tutorial.hud_show(player)
  arena_lib.HUD_send_msg("title", p_name, S("Try again!"), 3)

  if curr_phase == 4 then
    local sentries_left = p_tracker.sentries_left

    if sentries_left < 4 then
      local e_pos1 = vector.add(start_coords, vector.new(0, 0, -10))

      p_tracker.sentries_left = 3
      remove_entities(e_pos1, 30, "bl_tutorial:sentry")
      arena_lib.HUD_send_msg("broadcast", p_name, S("Sentry guns left: @1", p_tracker.sentries_left))

      core.after(2.5, function()
        if not p_tracker then return end
        spawn_sentries4(start_coords)
      end)
    end

  elseif curr_phase == 5 then
    local ball_pos = vector.add(start_coords, vector.new(0, 2.6, -12))
    remove_entities(ball_pos, 30, "bl_tutorial:sentry")

    for _, child in pairs(player:get_children()) do
      local ent_lua = child:get_luaentity()
      -- impossibile che ci siano altre entità o giocatorɜ, ma MT ogni tanto è in
      -- grado di trovare l'oggetto figlio senza trovare la definizione dell'entità..
      -- poco rotto. Da qui il primo controllo
      if ent_lua and ent_lua.name == "bl_tutorial:ball" then
        ent_lua:_destroy()
        p_tracker[5].prerequisites_satisfied = false
        core.add_entity(ball_pos, "bl_tutorial:ball")
        break
      end
    end

    core.after(2.5, function()
      if not p_tracker then return end
      spawn_sentries5(start_coords)
    end)
  end
end





----------------------------------------------
-------------------FASE 5---------------------
----------------------------------------------

function phase5(player)
  local p_name = player:get_player_name()
  local start_coords = tracker[p_name][5].start_coords
  local ball_pos = vector.add(start_coords, vector.new(0, 2.6, -12))

  remove_entities(ball_pos, 30, "bl_tutorial:sentry")
  remove_entities(ball_pos, 3, "bl_tutorial:ball")

  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("Well done! Now let's see how Touchdown works"))

  core.after(5, function()
    if not tracker[p_name] then return end

    core.add_entity(ball_pos, "bl_tutorial:ball")
    panel_lib.get_panel(p_name, "bl_scoreboard"):show()
    arena_lib.HUD_send_msg("title", p_name, S("To score... just grab the ball and bring it into the enemy goal post (in front of you)!"), 7)

    core.after(7, function()
      if not tracker[p_name] then return end

      spawn_sentries5(start_coords)
      arena_lib.HUD_send_msg("broadcast", p_name, S("Grab the ball and reach the goal post"))

      player:get_attach():remove()
    end)
  end)
end


function bl_tutorial.complete_phase5(p_name)
  tracker[p_name][5].prerequisites_satisfied = true
end





----------------------------------------------
-------------------FASE 6---------------------
----------------------------------------------

function phase6(player)
  local p_name = player:get_player_name()
  local arena = arena_lib.get_arena_by_player(p_name)
  local future_ball_pos = vector.add(tracker[p_name][6].start_coords, vector.new(-4, 0, -17.5))

  remove_entities(future_ball_pos, 3, "bl_tutorial:ball")

  audio_lib.play_sound("bl_crowd_cheer", {to_player = p_name})
  block_league.HUD_scoreboard_update_score(arena)

  -- metto a 0 dato che la metto a 99 all'inizio di ogni fase. Così blocca stamina_drain,
  -- che eseguo sotto con un ritardo di 0.3 onde evitare di beccare lo 0.1 dello
  -- stamina_drain precedente
  arena.players[p_name].stamina = 0

  core.after(0.3, function()
    if not tracker[p_name] then return end
    arena.players[p_name].stamina = 99
    block_league.stamina_drain(arena, p_name)
  end)

  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("And that's how you score!"))

  core.after(4, function()
    if not tracker[p_name] then return end
    arena_lib.HUD_send_msg("title", p_name, S("Have you noticed that your stamina decreases when you hold the ball? If it reaches zero, you'll go slower"))

    core.after(7, function()
      if not tracker[p_name] then return end
      arena_lib.HUD_send_msg("title", p_name, S("Now try to go through the rays of your team colour (you currently have the ball)"), 4)

      core.after(4, function()
        if not tracker[p_name] then return end
        arena_lib.HUD_send_msg("broadcast", p_name, S("Go through the blue rays"))
        player:get_attach():remove()
      end)
    end)
  end)
end



function bl_tutorial.reset_ball(ball, p_name)
  arena_lib.HUD_hide("broadcast", p_name)
  arena_lib.HUD_send_msg("title", p_name, S("Exactly: rays of your team colour reset the ball. The other ones will kill you though!"))

  local ball_pos = vector.add(tracker[p_name][6].start_coords, vector.new(-4, 0, -17.5))

  ball:set_pos(ball_pos)

  core.after(6, function()
    if not tracker[p_name] or tracker[p_name].completed then return end
    arena_lib.HUD_send_msg("title", p_name, S("Alright then. You're now ready to become the best Block Leaguer ever: godspeed!"), 6)

    core.after(6, function()
      if not tracker[p_name] then return end
      arena_lib.HUD_send_msg("broadcast", p_name, S("Returning to the world in @1...", 3))
      core.after(1, function()
        if not tracker[p_name] then return end
        arena_lib.HUD_send_msg("broadcast", p_name, S("Returning to the world in @1...", 2))
        core.after(1, function()
          if not tracker[p_name] then return end
          arena_lib.HUD_send_msg("broadcast", p_name, S("Returning to the world in @1...", 1))
          core.after(1, function()
            if not tracker[p_name] then return end
            local arena = arena_lib.get_arena_by_player(p_name)

            ball:remove()
            arena_lib.force_end(S("Block League"), "block_league", arena)
            achvmt_lib.award(p_name, "block_league:first_steps")
          end)
        end)
      end)
    end)
  end)
end



function bl_tutorial.unload(p_name)
  bl_tutorial.hud_remove(p_name)
  tracker[p_name] = nil

  local player = core.get_player_by_name(p_name)

  player:hud_set_flags({hotbar = true})

  if player:get_attach() then
    player:get_attach():remove()
  end
end



function anchor_player(player)
  local p_pos = player:get_pos()
  local p_y = player:get_look_horizontal()
  local dummy = core.add_entity(p_pos, "weapons_lib:dummy")

  player:set_attach(dummy, "", {x=0,y=-5,z=0}, {x=0, y=-math.deg(p_y), z=0})
end



function remove_entities(pos, radius, name)
  for _, obj in pairs(core.get_objects_inside_radius(pos, radius)) do
    if not obj:is_player() then
      local obj_name = obj:get_luaentity().name
      if obj_name == name then
        obj:remove()
      end
    end
  end
end



function spawn_sentries4(start_coords)
  local e_pos1 = vector.add(start_coords, vector.new(0, 0, -10))
  local e_pos2 = vector.add(e_pos1, vector.new(8, 0, 1))
  local e_pos3 = vector.add(e_pos1, vector.new(-8, 0, 1))
  local e_pos4 = vector.add(e_pos1, vector.new(0, 0, -11))
  local e_pos5 = vector.add(e_pos2, vector.new(0, 0, -10))
  local e_pos6 = vector.add(e_pos3, vector.new(0, 0, -10))

  --core.add_entity(e_pos1, "bl_tutorial:sentry") -- TODO: mettile una volta implementato lo scudo
  core.add_entity(e_pos2, "bl_tutorial:sentry")
  core.add_entity(e_pos3, "bl_tutorial:sentry")
  core.add_entity(e_pos4, "bl_tutorial:sentry")
  --core.add_entity(e_pos5, "bl_tutorial:sentry")
  --core.add_entity(e_pos6, "bl_tutorial:sentry")
end



function spawn_sentries5(start_coords)
  local e_pos1 = vector.add(start_coords, vector.new(0, 0, -10))
  local e_pos2 = vector.add(e_pos1, vector.new(8, 0, -2))
  local e_pos3 = vector.add(e_pos1, vector.new(-8, 0, -2))
  local e_pos4 = vector.add(e_pos1, vector.new(0, 0, -6))
  local e_pos5 = vector.add(e_pos2, vector.new(0, 0, -10))
  local e_pos6 = vector.add(e_pos3, vector.new(0, 0, -10))

  core.add_entity(e_pos1, "bl_tutorial:sentry")
  local e2 = core.add_entity(e_pos2, "bl_tutorial:sentry")
  local e3 = core.add_entity(e_pos3, "bl_tutorial:sentry")
  local e4 = core.add_entity(e_pos4, "bl_tutorial:sentry")
  core.add_entity(e_pos5, "bl_tutorial:sentry")
  core.add_entity(e_pos6, "bl_tutorial:sentry")

  e2:set_rotation(vector.new(0, math.pi, 0))
  e3:set_rotation(vector.new(0, math.pi, 0))
  e4:set_rotation(vector.new(0, math.pi, 0))
end
