import java.io.IOException;
import java.util.List;
import java.util.Scanner;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class BackendDeveloperTests {
  private FrontendInterface frontend;
  private TextUITester tester;

  @Test
  public void test1() {
    BackendInterface b = new Backend(new ISCPlaceholder<>());

    // invalid filename should throw an IOException
    try {
      b.readData("");
      Assertions.fail("readData() did not throw an exception when given an invalid filename."); // fails
                                                                                                // the
                                                                                                // JUnit
                                                                                                // test
    } catch (IOException e) {
      // Expected IOException
    } catch (Exception e) {
      Assertions.fail("readData() threw the wrong exception when given an invalid filename.");
    }

    // valid filename should not throw an exception
    try {
      b.readData("songs.csv");
      // No exception expected
    } catch (IOException e) {

      Assertions.fail("readData() threw an exception when given a valid filename.");
    }
  }

  @Test
  public void test2() {
    BackendInterface b = new Backend(new ISCPlaceholder<>());
    // valid filename should not throw an exception
    try {
      b.readData("songs.csv");
      // No exception expected
    } catch (IOException e) {

      Assertions.fail("readData() threw an exception when given a valid filename.");
    }
    b.filterEnergeticSongs(60); // Set a high energy filter
    List<String> rangeEnergetic = b.getRange(0, 100);
    b = new Backend(new ISCPlaceholder<>());
    try {
      b.readData("songs.csv");
      // No exception expected
    } catch (IOException e) {

      Assertions.fail("readData() threw an exception when given a valid filename.");
    }
    List<String> songsAfterReset = b.getRange(0, 100); // Attempt to get range after reset
    // Make sure reinitialization clears filters
    Assertions.assertNotEquals(songsAfterReset, rangeEnergetic,
        "These two lists should be different.");
  }

  @Test
  public void test3() {
    BackendInterface b = new Backend(new ISCPlaceholder<>());
    try {
      b.readData("songs.csv");
    } catch (IOException e) {
      Assertions.fail("readData() threw an exception when given a valid filename.");
    }

    // getRange() not called yet so filterEnergeticSongs() should not return any songs
    Assertions.assertTrue(b.filterEnergeticSongs(10).size() == 0);

    // getRange() called, and now filterEnergetic() can return energetic songs within range
    List<String> songs = b.getRange(10, 100); // list of songs with that range of loudness

    for (String song : b.filterEnergeticSongs(10)) {
      if (!songs.contains(song)) {
        Assertions
            .fail("After calling getRange(), filterEnergetic() returned a song not in that range.");
      }
    }
  }



  @Test
  public void test4() {

    BackendInterface b = new Backend(new ISCPlaceholder<>());
    try {
      b.readData("songs.csv");
    } catch (IOException e) {
      Assertions.fail("Failed to read data for test setup.");
    }


    int low = 20;
    int high = 50;
    List<String> results = b.getRange(low, high);

    // Assert that the returned list is not empty and within the expected range
    Assertions.assertFalse(results.isEmpty(), "Expected non-empty list for valid range.");

  }

  @Test
  public void test5() {
    BackendInterface b = new Backend(new ISCPlaceholder<>());
    try {
      b.readData("songs.csv");
      b.getRange(10, 100); // Setup range
    } catch (IOException e) {
      Assertions.fail("Setup failed due to IOException.");
    }

    List<String> fastSongs = b.fiveFastest();
    Assertions.assertTrue(fastSongs.size() == 5, "fiveFastest() should return 5 songs.");
  }


  @Test
  public void testIntegrationReadAndDisplayData() {

    String dataInput = "R\nsongs.csv\nG\n10-50\nQ\n";

    // Initialize the TextUITester with the test input
    TextUITester tester = new TextUITester(dataInput);


    BackendInterface backend = new Backend(new IterableRedBlackTree<>());


    FrontendInterface frontend = new Frontend(new Scanner(System.in), backend);

    // Run the command loop of the frontend to simulate the user interaction
    frontend.runCommandLoop();

    // Retrieve and check the captured output
    String output = tester.checkOutput();

    // Validate the output contains expected elements
    assertTrue(output.contains("Enter path to csv file to load:"));
    assertTrue(output.contains("Done reading file."));
    assertTrue(output.contains("5 songs found between 10-50:"));
  }

  @Test
  public void testIntegrationTopFiveFastestSongs() {
    String dataInput = "R\nsongs.csv\nG\n10-50\nD\nF\n80\nQ\n";

    // Initialize the TextUITester with the test input
    TextUITester tester = new TextUITester(dataInput);


    BackendInterface backend = new Backend(new IterableRedBlackTree<>());


    FrontendInterface frontend = new Frontend(new Scanner(System.in), backend);

    // Run the command loop of the frontend to simulate the user interaction
    frontend.runCommandLoop();

    // Retrieve and check the captured output
    String output = tester.checkOutput();
    System.out.print(output);
    assertTrue(output.contains("Enter path to csv file to load:"));
    assertTrue(output.contains("Done reading file."));
    assertTrue(output.contains("5 songs found between 10-50:"));
    assertTrue(output.contains("songs found between 10 - 50 with energy >= 80"));
      
  }
  
 


  


}
