#include "game_501.hpp"

#include <cstdlib>
#include <iostream>
#include <string>

namespace
{
void require(bool condition, const std::string &message)
{
    if (!condition)
    {
        std::cerr << "FAILED: " << message << '\n';
        std::exit(1);
    }
}

void throwDart(Game501 &game, const std::string &score)
{
    const auto result = game.addDart(score, "test");
    require(result.value("accepted", false), "kastet " + score + " accepterades inte");
}

void clearBoard(Game501 &game)
{
    game.markBoardClear();
}
} // namespace

int main()
{
    require(Game501::parseDart("t20")->value == 60, "T20 ska ge 60");
    require(Game501::parseDart("D20")->is_double, "D20 ska räknas som dubbel");
    require(Game501::parseDart("BULL")->is_double, "bull ska vara giltig double-out");
    require(Game501::parseDart("OUTER")->value == 25, "outer bull ska ge 25");
    require(!Game501::parseDart("T21"), "T21 ska nekas");

    Game501 checkout_game;
    checkout_game.start({"Ada"});
    for (int turn = 0; turn < 2; ++turn)
    {
        throwDart(checkout_game, "T20");
        throwDart(checkout_game, "T20");
        throwDart(checkout_game, "T20");
        clearBoard(checkout_game);
    }
    require(checkout_game.state()["players"][0]["score"] == 141, "två 180-turer ska lämna 141");
    throwDart(checkout_game, "T20");
    throwDart(checkout_game, "T19");
    throwDart(checkout_game, "D12");
    require(checkout_game.state()["status"] == "finished", "D12 ska checka ut 24");
    require(checkout_game.state()["winner"] == 0, "Ada ska vinna");

    Game501 bust_game;
    bust_game.start({"Linus"});
    for (int turn = 0; turn < 2; ++turn)
    {
        throwDart(bust_game, "T20");
        throwDart(bust_game, "T20");
        throwDart(bust_game, "T20");
        clearBoard(bust_game);
    }
    throwDart(bust_game, "T20");
    throwDart(bust_game, "T20");
    throwDart(bust_game, "D20");
    require(bust_game.state()["players"][0]["score"] == 141, "bust ska återställa turstartens poäng");
    require(bust_game.state()["awaiting_clear"], "bust ska avsluta turen");

    const auto undo = bust_game.undo();
    require(undo.value("accepted", false), "bustkastet ska kunna ångras");
    require(bust_game.state()["players"][0]["score"] == 21, "ångra ska återställa läget före bustkastet");
    require(bust_game.state()["current_turn"]["darts"].size() == 2, "två kast ska återstå efter ångra");

    Game501 multiplayer_game;
    multiplayer_game.start({"Anna", "Björn"});
    throwDart(multiplayer_game, "T20");
    throwDart(multiplayer_game, "T20");
    throwDart(multiplayer_game, "T20");
    require(multiplayer_game.state()["players"][0]["score"] == 321, "180 ska dras från första spelarens poäng");
    require(multiplayer_game.state()["active_player"] == 1, "turen ska gå till nästa spelare");
    require(multiplayer_game.state()["awaiting_clear"], "tre kast ska kräva tom tavla");
    clearBoard(multiplayer_game);
    throwDart(multiplayer_game, "S1");
    require(multiplayer_game.state()["players"][1]["score"] == 500, "andra spelarens kast ska registreras");
    require(multiplayer_game.undo().value("accepted", false), "andra spelarens kast ska gå att ångra");
    require(multiplayer_game.state()["players"][1]["score"] == 501, "ångra ska återställa andra spelarens poäng");

    std::cout << "game-501-tests: OK\n";
    return 0;
}
