<commit_before># frozen_string_literal: true

class RconAutocomplete
  attr_accessor :query, :reservation

  def initialize(reservation = nil)
    @reservation = reservation
  end

  def autocomplete(query)
    @query = query.downcase

    deep_suggestions = autocomplete_deep_suggestions

    return deep_suggestions if deep_suggestions

    suggestions = autocomplete_exact_start.sort_by { |command| command[:command] }

    return suggestions.first(5) if suggestions

    autocomplete_best_match.first(5).sort_by { |command| command[:command] }
  end

  def autocomplete_deep_suggestions
    send("autocomplete_deep_#{query.split.first}") if self.class.deep_complete_commands.any? { |command| query.start_with?(command[:command]) }
  end

  def autocomplete_deep_changelevel
    self.class.autocomplete_maps
        .select { |map_name| map_name.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |map_name| { command: "changelevel #{map_name}", description: 'Changes the map' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_exec
    self.class.league_configs
        .select { |config| config.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |config| { command: "exec #{config}", description: 'Executes a config' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_kick
    autocomplete_players
      .map do |ps|
        uid3 = SteamCondenser::Community::SteamId.community_id_to_steam_id3(ps.reservation_player.steam_uid.to_i)
        { command: "kickid \"#{uid3}\"", display_text: "kick \"#{ps.reservation_player.name}\"", description: "Kick #{ps.reservation_player.name}" }
      end
  end

  def autocomplete_deep_kickid
    autocomplete_deep_kick
  end

  def autocomplete_deep_ban
    autocomplete_players
      .map do |ps|
        community_id = ps.reservation_player.steam_uid
        { command: "banid 0 #{community_id} kick", display_text: "ban \"#{ps.reservation_player.name}\"", description: "Ban #{ps.reservation_player.name}" }
      end
  end

  def autocomplete_deep_banid
    autocomplete_deep_ban
  end

  def autocomplete_players
    PlayerStatistic
      .joins(:reservation_player)
      .order('lower(reservation_players.name) ASC')
      .where('reservation_players.reservation_id = ?', reservation.id)
      .where('player_statistics.created_at > ?', 90.seconds.ago)
      .to_a
      .uniq { |ps| ps.reservation_player.steam_uid }
  end

  def autocomplete_exact_start
    self.class.commands_to_suggest
        .select { |command| command[:command].start_with?(query) }
        .sort_by { |command| Text::Levenshtein.distance(command[:command], query) }
  end

  def autocomplete_best_match
    self.class.commands_to_suggest
        .sort_by { |command| Text::Levenshtein.distance(command[:command], query) }
  end

  def self.deep_complete_commands
    [
      { command: 'changelevel', description: 'Change the map' },
      { command: 'exec', description: 'Execute a config' },
      { command: 'kick', description: 'Kick a player by name' },
      { command: 'kickid', description: 'Kick a player by unique ID' },
      { command: 'ban', description: 'Ban a player by name' },
      { command: 'banid', description: 'Ban a player by unique ID' }
    ]
  end

  def self.league_configs
    %w[
      etf2l
      etf2l_6v6
      etf2l_6v6_5cp
      etf2l_6v6_ctf
      etf2l_6v6_koth
      etf2l_6v6_stopwatch
      etf2l_9v9
      etf2l_9v9_5cp
      etf2l_9v9_ctf
      etf2l_9v9_koth
      etf2l_9v9_stopwatch
      etf2l_bball
      etf2l_golden_cap
      etf2l_ultiduo

      rgl_6s_5cp_gc
      rgl_6s_5cp_match
      rgl_6s_5cp_match_half1
      rgl_6s_5cp_match_half2
      rgl_6s_5cp_scrim
      rgl_6s_koth_bo5
      rgl_6s_koth
      rgl_6s_koth_match
      rgl_6s_koth_scrim
      rgl_7s_koth_bo5
      rgl_7s_koth
      rgl_7s_stopwatch
      rgl_HL_koth_bo5
      rgl_HL_koth
      rgl_HL_stopwatch
      rgl_mm_5cp
      rgl_mm_koth_bo5
      rgl_mm_koth
      rgl_mm_stopwatch
      rgl_off

      ugc_HL_koth
      ugc_HL_standard
      ugc_HL_stopwatch
      ugc_6v_golden
      ugc_6v_koth
      ugc_6v_koth_overtime
      ugc_6v_standard
      ugc_6v_standard_overtime
      ugc_4v_stopwatch
      ugc_4v_golden
      ugc_4v_koth
      ugc_4v_koth_overtime
      ugc_4v_standard
      ugc_4v_standard_overtime
      ugc_4v_stopwatch
      ugc_off
      ugc_UD_ultiduo
    ]
  end

  def self.autocomplete_maps
    %w[
      cp_gullywash_f4a
      cp_gullywash_f5
      cp_metalworks
      cp_metalworks_f2
      cp_process_f9a
      cp_reckoner_rc6
      cp_snakewater_final1
      cp_sunshine
      koth_clearcut_b15d

      cp_granary_pro2
      cp_steel_f6
      cp_steel_f8
      cp_villa_b18
      koth_ashville_rc2d
      koth_bagel_rc5
      koth_cascade_rc2
      koth_lakeside_r2
      koth_product_final
      pl_vigil_rc7
      pl_vigil_rc8
      pl_swiftwater_final1
      pl_upward
    ]
  end
<commit_msg>Autocomplete whitelists<commit_after># frozen_string_literal: true

class RconAutocomplete
  attr_accessor :query, :reservation

  def initialize(reservation = nil)
    @reservation = reservation
  end

  def autocomplete(query)
    @query = query.downcase

    deep_suggestions = autocomplete_deep_suggestions

    return deep_suggestions if deep_suggestions

    suggestions = autocomplete_exact_start.sort_by { |command| command[:command] }

    return suggestions.first(5) if suggestions

    autocomplete_best_match.first(5).sort_by { |command| command[:command] }
  end

  def autocomplete_deep_suggestions
    send("autocomplete_deep_#{query.split.first}") if self.class.deep_complete_commands.any? { |command| query.start_with?(command[:command]) }
  end

  def autocomplete_deep_changelevel
    self.class.autocomplete_maps
        .select { |map_name| map_name.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |map_name| { command: "changelevel #{map_name}", description: 'Changes the map' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_exec
    self.class.league_configs
        .select { |config| config.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |config| { command: "exec #{config}", description: 'Executes a config' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_mp_tournament_whitelist
    self.class.league_whitelists
        .select { |whitelist| whitelist.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |whitelist| { command: "mp_tournament_whitelist #{whitelist}", description: 'Set the tournament whitelist' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_tftrue_whitelist_id
    self.class.whitelist_tf_whitelists
        .select { |whitelist| whitelist.downcase.start_with?(query.split[1..].join(' ')) }
        .map { |whitelist| { command: "tftrue_whitelist_id #{whitelist}", description: 'Download and set the latest whitelist from whitelist.tf' } }
        .sort_by { |command| command[:command] }
  end

  def autocomplete_deep_kick
    autocomplete_players
      .map do |ps|
        uid3 = SteamCondenser::Community::SteamId.community_id_to_steam_id3(ps.reservation_player.steam_uid.to_i)
        { command: "kickid \"#{uid3}\"", display_text: "kick \"#{ps.reservation_player.name}\"", description: "Kick #{ps.reservation_player.name}" }
      end
  end

  def autocomplete_deep_kickid
    autocomplete_deep_kick
  end

  def autocomplete_deep_ban
    autocomplete_players
      .map do |ps|
        community_id = ps.reservation_player.steam_uid
        { command: "banid 0 #{community_id} kick", display_text: "ban \"#{ps.reservation_player.name}\"", description: "Ban #{ps.reservation_player.name}" }
      end
  end

  def autocomplete_deep_banid
    autocomplete_deep_ban
  end

  def autocomplete_players
    PlayerStatistic
      .joins(:reservation_player)
      .order('lower(reservation_players.name) ASC')
      .where('reservation_players.reservation_id = ?', reservation.id)
      .where('player_statistics.created_at > ?', 90.seconds.ago)
      .to_a
      .uniq { |ps| ps.reservation_player.steam_uid }
  end

  def autocomplete_exact_start
    self.class.commands_to_suggest
        .select { |command| command[:command].start_with?(query) }
        .sort_by { |command| Text::Levenshtein.distance(command[:command], query) }
  end

  def autocomplete_best_match
    self.class.commands_to_suggest
        .sort_by { |command| Text::Levenshtein.distance(command[:command], query) }
  end

  def self.deep_complete_commands
    [
      { command: 'ban', description: 'Ban a player by name' },
      { command: 'banid', description: 'Ban a player by unique ID' },
      { command: 'changelevel', description: 'Change the map' },
      { command: 'exec', description: 'Execute a config' },
      { command: 'kick', description: 'Kick a player by name' },
      { command: 'kickid', description: 'Kick a player by unique ID' },
      { command: 'mp_tournament_whitelist', description: 'Set the item/weapon whitelist' },
      { command: 'tftrue_whitelist_id', description: 'Set and download the latest whitelist from whitelist.tf' }
    ]
  end

  def self.league_configs
    %w[
      etf2l
      etf2l_6v6
      etf2l_6v6_5cp
      etf2l_6v6_ctf
      etf2l_6v6_koth
      etf2l_6v6_stopwatch
      etf2l_9v9
      etf2l_9v9_5cp
      etf2l_9v9_ctf
      etf2l_9v9_koth
      etf2l_9v9_stopwatch
      etf2l_bball
      etf2l_golden_cap
      etf2l_ultiduo

      rgl_6s_5cp_gc
      rgl_6s_5cp_match
      rgl_6s_5cp_match_half1
      rgl_6s_5cp_match_half2
      rgl_6s_5cp_scrim
      rgl_6s_koth_bo5
      rgl_6s_koth
      rgl_6s_koth_match
      rgl_6s_koth_scrim
      rgl_7s_koth_bo5
      rgl_7s_koth
      rgl_7s_stopwatch
      rgl_HL_koth_bo5
      rgl_HL_koth
      rgl_HL_stopwatch
      rgl_mm_5cp
      rgl_mm_koth_bo5
      rgl_mm_koth
      rgl_mm_stopwatch
      rgl_off

      ugc_HL_koth
      ugc_HL_standard
      ugc_HL_stopwatch
      ugc_6v_golden
      ugc_6v_koth
      ugc_6v_koth_overtime
      ugc_6v_standard
      ugc_6v_standard_overtime
      ugc_4v_stopwatch
      ugc_4v_golden
      ugc_4v_koth
      ugc_4v_koth_overtime
      ugc_4v_standard
      ugc_4v_standard_overtime
      ugc_4v_stopwatch
      ugc_off
      ugc_UD_ultiduo
    ]
  end

  def self.league_whitelists
    %w[
      etf2l_whitelist_6v6.txt
      etf2l_whitelist_9v9.txt
      etf2l_whitelist_bball.txt
      etf2l_whitelist_ultiduo.txt

      rgl_6v6_s7.txt
      rgl_7v7_s9.txt
      rgl_9v9_s10.txt
      rgl_nr6s_s3.txt

      item_whitelist_ugc_4v4.txt
      item_whitelist_ugc_6v6.txt
      item_whitelist_ugc_hl.txt
      item_whitelist_ugc_ud.txt
    ]
  end

  def self.whitelist_tf_whitelists
    %w[
      etf2l_whitelist_6v6
      etf2l_whitelist_9v9
      etf2l_whitelist_bball
      etf2l_whitelist_ultiduo

      rgl_6v6
      rgl_7v7
      rgl_9v9
      rgl_nr6s

      item_whitelist_ugc_4v4
      item_whitelist_ugc_6v6
      item_whitelist_ugc_HL
      item_whitelist_ugc_UD
    ]
  end

  def self.autocomplete_maps
    %w[
      cp_gullywash_f4a
      cp_gullywash_f5
      cp_metalworks
      cp_metalworks_f2
      cp_process_f9a
      cp_reckoner_rc6
      cp_snakewater_final1
      cp_sunshine
      koth_clearcut_b15d

      cp_granary_pro2
      cp_steel_f6
      cp_steel_f8
      cp_villa_b18
      koth_ashville_rc2d
      koth_bagel_rc5
      koth_cascade_rc2
      koth_lakeside_r2
      koth_product_final
      pl_vigil_rc7
      pl_vigil_rc8
      pl_swiftwater_final1
      pl_upward
    ]
  end

{'fraction_non_alphanumeric': 0.0804093567251462, 'fraction_numerical': 0.021413828689370484, 'mean_word_length': 2.9811708319068813, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5810420', 'n_tokens_mistral': 4529, 'n_tokens_neox': 4354, 'n_words': 683}