local MT = minetest
local vMod = vm_lighting_wand
local locale = vMod.locale

local caster_cooldown = tonumber(MT.settings:get("vm_lighting_wand_cooldown") or 1)
local casters = {}

local txt = {
  not_enough_power = locale("Not enough power, feed the wand more burnables!"),
  out_of_range = locale("Out of range, feed the wand more burnables to level it up!"),
  is_protected = locale("Pointed node is protected"),
  cant_place = locale("Could not set/unset light at pointed node"),
  on_cooldown = locale("on cooldown please wait"),
  places = "places node",
  removes = "removes node",
  second = "second",
  seconds = "seconds",
  at = "at"
}

local pad = function(mes, left, right)
  left = left and left or true
  right = right and right or true
  local retval
  if left then
    retval = " "
  end
  retval = retval .. locale(mes)
  if right then
    retval = retval .. " "
  end
  return retval
end

-- Actually places the light node and logs it as a action
local place_light = function(lighting_node, lighting_pos, player)
  local player_name = player:get_player_name()
  -- do cost and subtract sun_power or error
  if not vMod.do_power_cost(player, lighting_pos) then
    vMod.play_failed_effects(player, txt.not_enough_power)
    return
  end
  MT.set_node(lighting_pos, { name = lighting_node })
  vMod.play_effects(player, lighting_pos)
  vMod.logger(player_name .. pad(txt.places) .. lighting_node .. pad(txt.at) .. MT.pos_to_string(lighting_pos))
end

-- undoes what place_lighting_node did
local remove_light = function(lighting_node, lighting_pos, player)
  local player_name = player:get_player_name()
  -- do cost and subtract sun_power or error
  if not vMod.do_power_cost(player, lighting_pos, true) then
    vMod.play_failed_effects(player, txt.not_enough_power)
    return
  end
  MT.remove_node(lighting_pos)
  vMod.logger(player_name .. pad(txt.removes) .. lighting_node .. pad(txt.at) .. MT.pos_to_string(lighting_pos))
end

-- main function called by the wand on_use()
vMod.cast_wand = function(player)
  if not player then
    return
  end
  local player_name = player:get_player_name()
  -- spam protection
  local now = minetest.get_gametime()
  if not casters[player_name] then
    casters[player_name] = now
  else
    if now - casters[player_name] < caster_cooldown then
      local msg = txt.on_cooldown .. " " .. caster_cooldown
      msg = msg .. (caster_cooldown == 1 and pad(txt.second) or pad(txt.seconds))
      MT.chat_send_player(player_name, "[LightingWand] " .. msg)
      return
    end
    casters[player_name] = now
  end

  local range = vMod.get_level(player).max_range
  local pointed_node = vMod.get_pointed_node(player, false, true, range)
  if not pointed_node then
    vMod.play_failed_effects(player, txt.out_of_range)
    return
  end

  -- ensure pos are set (should always be set)
  if not pointed_node.pos_above then
    vMod.play_failed_effects(player)
    return
  end

  -- protection, not sure if this is needed?
  if MT.is_protected(pointed_node.pos_above, player_name) then
    vMod.play_failed_effects(player, txt.is_protected)
    MT.record_protection_violation(pointed_node.pos_above, player_name)
    return
  end

  -- ensure a node was found
  if pointed_node.node_above and not vMod.is_ignored_onlighting(pointed_node.node_above.name) then
    local node_light
    if pointed_node.node_above.drawtype == "airlike" then
      node_light = vMod.air_light
    end
    if pointed_node.node_above.drawtype == "liquid" then
      node_light = vMod.water_light
    end

    if node_light then
      local fn
      if pointed_node.node_above.name == node_light then
        remove_light(node_light, pointed_node.pos_above, player)
      else
        place_light(node_light, pointed_node.pos_above, player)
      end
      return
    end
  else
    vMod.play_failed_effects(player, txt.cant_place)
  end
end
