#include <Replay.h>
#include <regex>
#include <iostream>
#include <sstream>
#include <stdexcept>

ReplayGame::ReplayGame(Game::create_func func, std::string orig)
{
    recording.exceptions( std::ifstream::failbit | std::ifstream::badbit);
    recording.open(orig);
    std::cerr << "Replaying! Ignoring limits and not starting actual game" << std::endl;
    std::string line;
    std::smatch match;
    std::getline(recording,line);
    do {
        std::cerr << "Checking: " << line << "#" << std::endl;
        if (!std::regex_match(line,match,std::regex("^Player: (.*)$")) || match.size() != 2) {
            throw std::runtime_error("Invalid record file contains no players");
        }
        replayMoves.push_back(std::vector<std::string>());;
        std::getline(recording,line);
    } while (std::regex_match(line,std::regex("^Player: .*$")));
    fetchTurns(func);
}

void ReplayGame::fetchTurns(Game::create_func func) {
    std::string line;
    std::smatch match;

    while (!recording.eof()) {
        std::getline(recording,line);
        if (!std::regex_match(line,match,std::regex("^Next player: ([0-9]*)$")) || match.size() != 2) {
            throw std::runtime_error("Failed to parse player record in replay file!");
        }
        Record r;
        std::stringstream(match[1]) >> r.player;

        std::getline(recording,line);
        if (!std::regex_match(line,match,std::regex("^Board: (.*)$")) || match.size() != 2) {
            throw std::runtime_error("Failed to parse board record in replay file!");
        }
        r.board = match[1];

        std::getline(recording,line);
        if (!std::regex_match(line,match,std::regex("^Move: (.*)$")) || match.size() != 2) {
            throw std::runtime_error("Failed to parse move record in replay file!");
        }
        r.move = match[1];
        records.push_back(r);
        replayMoves.at(r.player).push_back(r.move);
        //Discard sepeartor line
        try {
            if (!recording.eof())
                std::getline(recording,line);
        } catch (std::exception &f) {
            std::cerr << "Caught!" << std::endl;
            //TODO: really handle! Happens on EOF
        }
    }
    std::cerr << "Loaded " << records.size() << " turns" << std::endl;
    curRecord = records.begin();
    origGame = std::unique_ptr<Game>(func(replayMoves.size(),curRecord->board));
}

//I don't care about the move ... just reinitialize the next state
std::tuple<Game::MoveResult, std::string> ReplayGame::move(const std::string& mov) {
    auto ret = origGame->move(mov);
    if (curRecord+1 == records.end() && std::get<0>(ret) == MoveResult::OK)
        return result(MoveResult::End);
    curRecord++;
    return ret;
}

unsigned ReplayGame::currentPlayer() const {
    return curRecord->player;
}

std::string ReplayGame::serialize() const {
    return origGame->serialize();
}

std::vector<std::unique_ptr<RePlayer>> ReplayGame::players() {
    std::vector<std::unique_ptr<RePlayer>> rp;
    for (auto v : replayMoves) {
        rp.emplace_back(std::make_unique<RePlayer>(v));
        for (auto e : v)
            std::cerr << e << ", ";
        std::cerr << std::endl;
    }
    return rp;
}
