// Pruebas públicas del paso 5. No compila hasta que declaren average y best.
#include <cassert>
#include <cmath>
#include <iostream>
#include <string>

#include "grade_book.h"

// Recibe const&: si average o best no son const, esto no compila.
double read_average(const GradeBook& book) {
    return book.average();
}

std::string read_best(const GradeBook& book) {
    return book.best();
}

bool close_to(double a, double b) {
    return std::fabs(a - b) < 1e-9;
}

void test_empty() {
    const GradeBook book{};
    assert(close_to(read_average(book), 0.0));
    assert(read_best(book).empty());
}

void test_average_is_not_integer_division() {
    GradeBook book;
    assert(book.add("Ana", 14));
    assert(book.add("Luis", 15));
    assert(close_to(read_average(book), 14.5));
}

void test_best() {
    GradeBook book;
    assert(book.add("Ana", 0));
    assert(read_best(book) == "Ana");
    assert(book.add("Luis", 12));
    assert(book.add("Rosa", 17));
    assert(book.add("Omar", 3));
    assert(read_best(book) == "Rosa");
    assert(close_to(read_average(book), 8.0));
}

void test_tie_keeps_the_first() {
    GradeBook book;
    assert(book.add("Ana", 18));
    assert(book.add("Luis", 18));
    assert(read_best(book) == "Ana");
}

void test_follows_changes() {
    GradeBook book;
    assert(book.add("Ana", 10));
    assert(book.add("Luis", 20));
    assert(book.remove("Luis"));
    assert(read_best(book) == "Ana");
    assert(close_to(read_average(book), 10.0));
    assert(book.set_grade("Ana", 4));
    assert(close_to(read_average(book), 4.0));
    assert(book.remove("Ana"));
    assert(close_to(read_average(book), 0.0));
    assert(read_best(book).empty());
}

int main() {
    test_empty();
    test_average_is_not_integer_division();
    test_best();
    test_tie_keeps_the_first();
    test_follows_changes();
    std::cout << "paso 5: todas las pruebas pasaron\n";
    return 0;
}
