# frozen_string_literal: true require "csv" module EuchreCamp module Services class TournamentCsvImporter # Map table names to numeric IDs TABLE_NAME_MAP = { "Clubs" => 1, "Hearts" => 2, "Diamonds" => 3, "Spades" => 4, "Stars" => 5 }.freeze def initialize(event_id:) @event_id = event_id @rom = EuchreCamp::App["persistence.rom"] @matches_repo = EuchreCamp::App["repositories.matches"] @teams_repo = EuchreCamp::App["repositories.teams"] @events_repo = EuchreCamp::App["repositories.events"] @rounds_repo = EuchreCamp::App["repositories.tournament_rounds"] @bracket_matchups_repo = EuchreCamp::App["repositories.bracket_matchups"] end def import(csv_file_path) results = { matches_created: 0, teams_created: 0, rounds_created: 0, errors: [] } begin event = @events_repo.by_id(@event_id) CSV.foreach(csv_file_path, headers: true, header_converters: :symbol) do |row| begin process_row(row, event, results) rescue => e results[:errors] << "Row #{row}: #{e.message}" end end rescue => e results[:errors] << "Fatal error: #{e.message}" end results end private def process_row(row, event, results) # Extract data from CSV row round_number = row[:round].to_i table_name = row[:table] seat_1_name = row[:seat_1]&.strip seat_3_name = row[:seat_3]&.strip odds_points = row[:odds_points].to_i seat_2_name = row[:seat_2]&.strip seat_4_name = row[:seat_4]&.strip evens_points = row[:evens_points].to_i winner = row[:winner]&.strip&.downcase # Validate required fields unless seat_1_name && seat_3_name && seat_2_name && seat_4_name raise "Missing player names in row" end # Find or create players player_1 = find_or_create_player(seat_1_name) player_2 = find_or_create_player(seat_3_name) player_3 = find_or_create_player(seat_2_name) player_4 = find_or_create_player(seat_4_name) # Find or create teams team_1 = @teams_repo.find_or_create(@event_id, player_1[:id], player_2[:id], "#{seat_1_name} + #{seat_3_name}") team_2 = @teams_repo.find_or_create(@event_id, player_3[:id], player_4[:id], "#{seat_2_name} + #{seat_4_name}") results[:teams_created] += 1 if team_1[:created_at] == team_2[:created_at] # Rough check for new teams # Find or create round round = find_or_create_round(round_number) # Map table name to number table_number = TABLE_NAME_MAP[table_name] || table_name.to_i if table_number == 0 raise "Unknown table name: #{table_name}" end # Determine winner based on scores or explicit winner column team_1_score = odds_points team_2_score = evens_points # Verify winner matches scores if explicitly stated if winner if winner == "odds" && team_1_score <= team_2_score results[:errors] << "Warning: Row claims Odds won but score is #{team_1_score}-#{team_2_score}" elsif winner == "evens" && team_2_score <= team_1_score results[:errors] << "Warning: Row claims Evens won but score is #{team_1_score}-#{team_2_score}" end end # Create match match_data = { team_1_p1_id: player_1[:id], team_1_p2_id: player_2[:id], team_1_score: team_1_score, team_2_p1_id: player_3[:id], team_2_p2_id: player_4[:id], team_2_score: team_2_score, played_at: Time.now, status: 'completed' } match = @matches_repo.create(match_data) results[:matches_created] += 1 # Create bracket matchup entry bracket_data = { round_id: round[:id], event_id: @event_id, team_1_id: team_1[:id], team_2_id: team_2[:id], table_number: table_number, bracket_position: table_number, status: 'completed' } @bracket_matchups_repo.create(bracket_data) # Queue Elo calculation EuchreCamp::Jobs::CalculateEloJob.perform_later(match[:id]) rescue => e raise "Error processing row: #{e.message}" end def find_or_create_player(name) return nil unless name player = @rom.relations[:players].where(name: name).one if player player else # Create player with default rating @rom.relations[:players].insert(name: name, rating: 0, current_elo: 1000) @rom.relations[:players].where(name: name).one end end def find_or_create_round(round_number) round = @rom.relations[:tournament_rounds].where(event_id: @event_id, round_number: round_number).one if round round else @rounds_repo.create( event_id: @event_id, round_number: round_number, status: 'completed' ) end end end end end