#include <maps/libs/log8/include/log8.h>
#include <maps/libs/common/include/exception.h>
#include <maps/libs/cmdline/include/cmdline.h>

#include <maps/libs/json/include/value.h>

#include <maps/wikimap/mapspro/services/autocart/pipeline/libs/config/include/config.h>

#include <string>
#include <iomanip>
#include <fstream>
#include <sstream>

using namespace maps::wiki::autocart::pipeline;

namespace {

static const std::string TASKS = "tasks";
static const std::string KNOWN_SOLUTIONS = "knownSolutions";

struct PoolStatistics {
    size_t suitesCount = 0;
    size_t realTasksCount = 0;
    size_t goldenTasksCount = 0;
};

PoolStatistics getPoolStatistics(const std::string& path) {
    maps::json::Value suites = maps::json::Value::fromFile(path);

    PoolStatistics poolStatistics;
    poolStatistics.suitesCount = suites.size();
    for (const maps::json::Value& suite : suites) {
        for (const maps::json::Value& task : suite[TASKS]) {
            if (task.hasField(KNOWN_SOLUTIONS)) {
                poolStatistics.goldenTasksCount++;
            } else {
                poolStatistics.realTasksCount++;
            }
        }
    }
    return poolStatistics;
}

std::string createAssessorsValidationComment(
    const PoolStatistics& poolStatistics, const AssessorsConfig& config)
{
    size_t tasksCount = poolStatistics.realTasksCount + poolStatistics.goldenTasksCount;
    double budget = tasksCount * config.rewardPerTask();
    std::stringstream ss;
    ss << std::fixed << std::setprecision(2);
    ss << "Переведите тикет **!!(зел)в работу!!**, чтобы запустить валидацию асессорами, ";
    ss << " или **!!закройте!!** его, чтобы отменить дальнейшее выполнение процесса.\n";
    ss << "Параметры валидации:\n";
    ss << "* Общее количество заданий: " << tasksCount << "\n";
    ss << "  * Количество реальных заданий: " << poolStatistics.realTasksCount << "\n";
    ss << "  * Количество контрольных заданий: " << poolStatistics.goldenTasksCount << "\n";
    ss << "* Количество страниц с заданиями: " << poolStatistics.suitesCount << "\n";
    ss << "* Количество заданий на одной странице: " << config.tasksCount() << "\n";
    ss << "* Частота показа страниц с контрольными заданиями: " << config.goldenSuitesFrequency() << "\n";
    ss << "* Количество контрольных заданий на контрольной странице: " << config.goldenTasksCount() << "\n";
    ss << "* Цена за одно задание: " << config.rewardPerTask() << " руб.\n";
    ss << "* Бюджет валидации в Я.Толоке: " << budget << " руб.";

    return ss.str();
}

} // namespace

int main(int argc, const char** argv)
try {
    maps::cmdline::Parser parser("Create assessors validation comment");

    maps::cmdline::Option<std::string> suitesJsonPath = parser.string("suites")
        .required()
        .help("Path to json file with suites");

    maps::cmdline::Option<std::string> assessorsConfigPath = parser.string("assessors_config")
        .required()
        .help("Path to tolokers config file");

    maps::cmdline::Option<std::string> outputPath = parser.string("output")
        .required()
        .help("Path to output text file with comment");

    parser.parse(argc, const_cast<char**>(argv));


    INFO() << "Loading assessors config: " << assessorsConfigPath;
    AssessorsConfig assessorsConfig(assessorsConfigPath);

    INFO() << "Loading suites from file: " << suitesJsonPath;
    PoolStatistics poolStatistics = getPoolStatistics(suitesJsonPath);

    INFO() << "Creating Startrek comment text";
    std::string comment = createAssessorsValidationComment(poolStatistics, assessorsConfig);

    INFO() << "Saving comment into file: " << outputPath;
    std::ofstream ofs(outputPath);
    REQUIRE(ofs.is_open(), "Failed to open file: " + outputPath);
    ofs << comment;
    ofs.close();

    return EXIT_SUCCESS;
}
catch (const maps::Exception& e) {
    INFO() << e;
    return EXIT_FAILURE;
}
catch (const std::exception& e) {
    INFO() << e.what();
    return EXIT_FAILURE;
}
catch (...) {
    INFO() << "Caught unknown exception";
    return EXIT_FAILURE;
}
