# @author Wiley Bui (https://github.com/wileybui)

require "singleton"

module Database
  # UsersRanksSingleton class mainly sets and checks a user's rank, which is located on
  # the database & cache. Otherwise, it returns the default rank if the user ID could not be
  # found from cache.
  class UsersRanksSingleton
    include Singleton

    # Initializes the UsersRanksSingleton instance.
    # It calls save_to_cache_from_db() to save the database values to the cache.
    def initialize()
      puts("- Initializing #{self.class}")
      @ranks = {}
      @database = Database::DatabaseManagerSingleton.instance()
      save_to_cache_from_db()
    end

    # Retrieves all records from the USERS_RANK_TABLE and cache it to the
    # instance variable @ranks. Its keys hold the user IDs and its values hold
    # the its corresponding ranks.
    def save_to_cache_from_db()
      @database.get_all_users_ranks().each { |user_id, user_rank|
        @ranks[user_id] = { :rank => user_rank }
      }
    end

    # Checks if the user's ID has the Bot's Admin rank.
    #
    # @param user_id [int] User's ID.
    # @return [bool] If the user's rank is >= 10.
    def has_bot_admin_rank?(user_id)
      return (@ranks.include? user_id) && (@ranks[user_id][:rank] >= 10)
    end

    # Checks if the user's ID has the Bot's Game Operator rank.
    #
    # @param user_id [int] User's ID.
    # @return [bool] If the user's rank is >= 5.
    def has_bot_game_operator_rank?(user_id)
      return (@ranks.include? user_id) && (@ranks[user_id][:rank] >= 5)
    end

    # Checks if the user's ID has the Bot's Regular rank.
    #
    # @param user_id [int] User's ID.
    # @return [bool] If the user's rank is not banned.
    def has_bot_regular_rank?(user_id)
      return !has_bot_banned_rank?(user_id)
    end

    # Checks if the user's ID has the Bot's Banned rank.
    #
    # @param user_id [int] User's ID.
    # @return [bool] If the user's rank is <= 0.
    def has_bot_banned_rank?(user_id)
      return (@ranks.include? user_id) && (@ranks[user_id][:rank] <= 0)
    end

    # Gets the rank of the given user ID.
    #
    # @param user_id [int] User's ID.
    # @return [int] The user's rank. If user ID doesn't exist in cache, then it returns 1 as a regular rank.
    def get_rank(user_id)
      if (@ranks[user_id] && @ranks[user_id][:rank])
        return @ranks[user_id][:rank]
      end
      return 1
    end

    # Updates the rank of the specified users.
    #
    # @param rank [int] To-be-updated rank for every user.
    # @param users [Array] A list of users to be updated with the specified rank.
    def update_rank(rank, users)
      if (users.class == Integer)
        users = [users]
      end

      users.each { |id|
        id = id.to_i
        @database.update_user_rank(rank, id)
        if (@ranks.include?(id))
          @ranks[id][:rank] = rank
        else
          @ranks[id] = { :rank => rank }
        end
      }
    end
  end
end
