#include "../Pieces/Generator.h"
#include "../Pieces/PiecesFiles.h"

#include <chrono>
#include <filesystem>
#include <cmath>

static const int BENCHMARK_PIECES_SIZE = 15;

void benchmarking(int min_size, int max_size);


int main(int argc, char** argv) {
    std::srand(std::time(NULL));

    #ifdef DEBUG
        std::cout << "IMPORTANT: You are currently in debug mode, debug mode has lowest optimization settings and thus yields worse benchmarking results, to switch to release mode, type 'xmake f -m debug'." << std::endl;
    #endif

    benchmarking(1, BENCHMARK_PIECES_SIZE);

    return 0;
}


void benchmarking(int min_size, int max_size) {
    using std::chrono::high_resolution_clock;
    using std::chrono::duration_cast;
    using std::chrono::duration;
    using std::chrono::milliseconds;

    std::cout << "| n | Number | Generation | File storing | File retrieving | File size |" << std::endl;
    std::cout << "| -: | -: | :-: | :-: | :-: | -: |" << std::endl;

    Generator gen;
    PiecesFiles pf;

    auto t1 = high_resolution_clock::now();
    auto t2 = high_resolution_clock::now();
    duration<double, std::milli> ms_double;
    bool ok;

    for (int i = min_size; i <= max_size; i++) {
        std::cout << "| " << i;

        t1 = high_resolution_clock::now();
        std::vector<Polyomino> polyominoes = gen.generatePolyominoes(i);
        t2 = high_resolution_clock::now();
        ms_double = t2 - t1;
        std::cout << " | " << polyominoes.size();
        std::flush(std::cout);
        std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
        std::flush(std::cout);

        t1 = high_resolution_clock::now();
        ok = pf.savePieces(i, polyominoes);
        t2 = high_resolution_clock::now();
        ms_double = t2 - t1;
        std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
        std::flush(std::cout);

        if (!ok) {
            std::cerr << "\nERROR: Could not save pieces to file." << std::endl;
            return;
        }

        polyominoes.clear();
        polyominoes.shrink_to_fit();

        std::vector<Piece> pieces;
        std::vector<int> convexPieces;
        std::vector<int> holelessPieces;
        std::vector<int> otherPieces;

        t1 = high_resolution_clock::now();
        ok = pf.loadPieces(i, pieces, convexPieces, holelessPieces, otherPieces);
        t2 = high_resolution_clock::now();
        ms_double = t2 - t1;
        std::cout << " | " << (int) ms_double.count() / 1000 << "s " << std::fmod(ms_double.count(), 1000) << "ms";
        std::flush(std::cout);

        if (!ok) {
            std::cerr << "\nERROR: Could not load pieces from file." << std::endl;
            return;
        }

        pieces.clear();
        pieces.shrink_to_fit();
        convexPieces.clear();
        convexPieces.shrink_to_fit();
        holelessPieces.clear();
        holelessPieces.shrink_to_fit();
        otherPieces.clear();
        otherPieces.shrink_to_fit();

        std::string filePath;
        pf.getFilePath(i, filePath);
        int fileSize = std::filesystem::file_size(filePath);
        std::cout << " | " << fileSize << " bytes |" << std::endl;
        std::flush(std::cout);
    }
}
