class ActiveGenie::Ranking::FreeForAll

def self.call(...)

def self.call(...)
  new(...).call
end

def battle(player_a, player_b)

def battle(player_a, player_b)
  result = ActiveGenie::Battle.call(
    player_a.content,
    player_b.content,
    @criteria,
    config: @config
  )
  winner, loser = case result['winner']
                  when 'player_a' then [player_a, player_b, result['reasoning']]
                  when 'player_b' then [player_b, player_a, result['reasoning']]
                  when 'draw' then [nil, nil, result['reasoning']]
                  end
  ActiveGenie::Logger.call({
                             code: :free_for_all_battle,
                             player_ids: [player_a.id, player_b.id],
                             winner_id: winner&.id,
                             loser_id: loser&.id,
                             reasoning: result['reasoning']
                           })
  [winner, loser]
end

def build_report

def build_report
  report = {
    free_for_all_id:,
    battles_count: matches.size,
    duration_seconds: Time.now - @start_time,
    total_tokens: @total_tokens
  }
  ActiveGenie::Logger.call({ code: :free_for_all_report, **report })
  report
end

def call

def call
  ActiveGenie::Logger.with_context(log_context, observer: method(:log_observer)) do
    matches.each do |player_a, player_b|
      winner, loser = battle(player_a, player_b)
      update_players_score(winner, loser)
    end
  end
  build_report
end

def free_for_all_id

def free_for_all_id
  eligible_ids = @players.eligible.map(&:id).join(',')
  ranking_unique_key = [eligible_ids, @criteria, @config.to_json].join('-')
  Digest::MD5.hexdigest(ranking_unique_key)
end

def initialize(players, criteria, config: {})

def initialize(players, criteria, config: {})
  @players = players
  @criteria = criteria
  @config = config
  @start_time = Time.now
  @total_tokens = 0
end

def log_context

def log_context
  { free_for_all_id: }
end

def log_observer(log)

def log_observer(log)
  @total_tokens += log[:total_tokens] if log[:code] == :llm_usage
end

def matches

For example, if A is better than B, and B is better than C, then battle between A and C should be auto win A
TODO: reduce the number of matches based on transitivity.
def matches
  @players.eligible.combination(2).to_a
end

def update_players_score(winner, loser)

def update_players_score(winner, loser)
  return if winner.nil? || loser.nil?
  if winner.nil? || loser.nil?
    player_a.draw!
    player_b.draw!
  else
    winner.win!
    loser.lose!
  end
end