import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.util.ArrayList;
import java.util.Scanner;
import java.lang.Math;

/**
 * The Tournament class contains code to read lines of 
 * (participant name, integer value) pairs from a file and create an ArrayList
 * of those pairs.  Every line in the file must contain one or more
 * (participant name, integer value) pairs in full. In other words, every line
 * must contain an even number of tokens; no pairs should be split across
 * multiple lines.
 * 
 * @author Alyce Brady
 * @version 12 December 2025
 */
public class Tournament 
{
    private int numRounds;
    private int numByes;

    /** Constructs an object that represents a tournament of players.
     */
    public Tournament()
    {
        this.numRounds = 0;
        this.numByes = 0;
    }

    /** Runs a simulated tournament, asking the user for files containing
     *  rankings and scores, identifying initial match-ups and byes, and
     *  showing match-ups and then scores for each round.
     *      @throw java.io.IOException if there are errors reading files
     */
    public void runTournament() throws java.io.IOException
    {
        int round = 1;
        K_SimpleAL<Matchup> allResults = new K_SimpleAL<>();

        // Read in the rankings and print them.
        K_OrderedList<ParticipantInfo> rankings = reportRankings();

        // Make a copy of the rankings to keep track of the active
        // participants as the tournament progresses.
        K_SimpleAL<ParticipantInfo> active = new K_SimpleAL<>();
        for ( ParticipantInfo participant : rankings )
            active.add(participant);

        // Determine how many rounds we'll need, and whether there are
        // any byes.
        setRoundsAndByes(rankings);
        if ( this.numByes > 0 )
        {
            // There are byes -- run the partial bye round.
            allResults = runByeRound(rankings);

/*
            // Modify the list of active participants, removing the losers
            // from the previous round.
            for ( Matchup result : allResults )
                active.remove(result.getLoser());

            round++;
                // YOU NEED TO ADD CODE HERE!
*/
        }

        // Handle the first full round (might be Round 1 or Round 2).
        // YOU NEED TO ADD CODE HERE!

    }

    /** Read in the rankings from a file and print and return them.
     *    @return a list of participants, ordered by ranking
     *    @throw java.io.IOException if there are errors reading files
     */
    public K_OrderedList<ParticipantInfo> reportRankings()
            throws java.io.IOException
    {
        // Get the name of the rankings file and read it in.
        String filename =
            ValidatedInputReader.getString("Enter name of rankings file: ",
                    "e.g., 18rankings.txt or 16rankings.txt");
        ParticipantReader rankingsReader = new ParticipantReader();
        K_OrderedList<ParticipantInfo> rankings =
                    rankingsReader.readParticipantInfo(filename);

        // Print the participants and their rankings, in order of ranking.
        System.out.println("Initial Rankings:");
            // YOU NEED TO ADD CODE HERE!
        System.out.println();

        // Return the rankings list.
        return rankings;
    }

    /** Determines the number of rounds that will be needed given the total
     *  number of participants as well as the number of byes required (if
     *  any) for Round 1.
     *    @param rankings the list of rankings
     */
    private void setRoundsAndByes(K_SimpleAL<ParticipantInfo> rankings)
    {
        int numParticipants = rankings.size();

        // The number of rounds is the log base 2 of the number of players.
        // The Math.log function returns the natural logarithm (ln).
        // log2(N) can be achieved with ln(N)/ln(2).
        // (Recent versions of Java have a log2 function; older ones do not.)
        this.numRounds = (int)Math.ceil(Math.log(numParticipants) /
                                   Math.log(2));

        // Number of byes is how many people are missing from a full power
        // of 2.
        this.numByes = ((int)Math.pow(2, this.numRounds)) - numParticipants;

        System.out.println("Number of Rounds: " + this.numRounds);
        System.out.println("Number of Byes: " + this.numByes);
        System.out.println();
    }

    /** Runs a bye round for a subset of participants.  This method should
     *  only be called if the number of participants is not an even power of
     *  2 and so a bye round is necessary.
     *    @param list the list of participants and rankings
     *    @return the scores from the bye round
     *    @throw java.io.IOException if there are errors reading files
     */
    public K_SimpleAL<Matchup> runByeRound(K_SimpleAL<ParticipantInfo> list)
            throws java.io.IOException
    {
        // Print the first-round byes.  These are the highest ranked
        // participants who do not have to participate in this round.
        System.out.println("First-Round Byes:");
        for ( int i = 0; i < this.numByes; i++ )
            System.out.println(list.get(i).rankThenName());
        System.out.println();

        // Make a list of active participants for this round.
        K_SimpleAL<ParticipantInfo> active = new K_OrderedList<>();
            // YOU NEED TO ADD CODE HERE!

/*
        // Get the match-ups and print.
        K_SimpleAL<Matchup> matchups = determineMatchups(active);
        printMatchups(matchups, "Round 1");

        // Get and print the scores from the bye round (Round 1);
        K_SimpleAL<Matchup> allResults = reportScores(1, active);
        return allResults;
*/
        // STUB CODE SO THAT IT COMPILES WHILE REAL CODE IS COMMENTED OUT.
        return null;

    }

    /** Reads and prints the scores from any given round.
     *    @param round  the current round number (1..total_Number_of_Rounds)
     *    @return the scores from the given round
     *    @throw java.io.IOException if there are errors reading files
     */
    private K_SimpleAL<Matchup> reportScores(int round,
                                    K_SimpleAL<ParticipantInfo> participants)
            throws java.io.IOException
    {
        // Get and print the scores from the given round.
        MatchupReader scoresReader = new MatchupReader();
        String filename = getScoresFilename(round);
        K_SimpleAL<Matchup> allResults = 
                    scoresReader.readScores(filename, participants);
        printScores(allResults, round);
        return allResults;
    }

    /** Determines match-ups for the next round of play.
     *    @param active the list of active participants in the next round
     *    @return the list of match-ups
     */
    public K_SimpleAL<Matchup>
                determineMatchups(K_SimpleAL<ParticipantInfo> active)
    {
        K_SimpleAL<Matchup> matchups = new K_SimpleAL<>();

            // YOU NEED TO ADD CODE HERE!

        return matchups;
    }

    /** Prompts the user for the filename of the file containing scores for
     * the given round.
     *    @param roundNumber  the round for which scores are needed
     *    @return the name of the file containing the round's scores
     */
    public String getScoresFilename(int roundNumber)
    {
        String suggestedName = 
                    "e.g., byeRoundScores.txt or fullRoundScores.txt";
        String filename =
            ValidatedInputReader.getString("File containing Round " +
                    roundNumber + " results: ", suggestedName);
        return filename;
    }

    public void printMatchups(K_SimpleAL<Matchup> matchups, String whichRound)
    {
        System.out.println(whichRound + " Match-Ups:");

            // YOU NEED TO ADD CODE HERE!

        System.out.println();
    }

    public void printScores(K_SimpleAL<Matchup> allResults, int whichRound)
    {
        System.out.println("Round " + whichRound + " Scores:");

            // YOU NEED TO ADD CODE HERE!

        System.out.println();
    }

    public static void main(String[] args) throws java.io.IOException
    {
        Tournament tourney = new Tournament();
        tourney.runTournament();
    }

}
