#include "stats.h"

#include <maps/wikimap/mapspro/libs/assessment/impl/sql_helpers.h>
#include <maps/wikimap/mapspro/libs/assessment/impl/magic_strings.h>

namespace maps::wiki::assessment::samples {

namespace {

SampleInfo::AssessorStats makeSampleAssessorStats(const pqxx::row& row)
{
    return {
        row["uid"].as<TUid>(),
        row["graded_units"].as<uint64_t>(),
        chrono::parseSqlDateTime(row["recent_graded_at"].c_str())
    };
}

UnitGradeStats makeUnitGradeStats(const pqxx::row& row)
{
    return {
        .unitId = row[sql::col::UNIT_ID].as<TId>(),
        .correct = row["correct"].as<unsigned>(),
        .incorrect = row["incorrect"].as<unsigned>()
    };
}

std::string gradeValueCount(pqxx::transaction_base& txn, Grade::Value value)
{
    return "COUNT(" + sql::col::GRADE_ID + ") FILTER(WHERE " +
        sql::col::VALUE + " = " + sqlEnumToString(txn, value) + ")";
}

} // namespace

std::vector<SampleInfo::AssessorStats> loadAssessorsStats(
    pqxx::transaction_base& txn,
    TId sampleId)
{
    const auto query =
        "SELECT " +
            sql::col::ACQUIRED_BY + " as uid, "
            "COUNT(" + sql::col::GRADE_ID + ") as graded_units, " +
            "MAX(" + sql::col::ACQUIRED_AT + ") as recent_graded_at "
        "FROM " +
            sql::table::SAMPLE_TASK + " "
        "WHERE " +
            sql::col::SAMPLE_ID + " = " + std::to_string(sampleId) + " AND " +
            sql::col::GRADE_ID + " IS NOT NULL "
        "GROUP BY " +
            sql::col::ACQUIRED_BY + " "
        "ORDER BY " +
            sql::col::ACQUIRED_BY;

    std::vector<SampleInfo::AssessorStats> assessorsStats;
    for (const auto& row : txn.exec(query)) {
        assessorsStats.emplace_back(makeSampleAssessorStats(row));
    }
    return assessorsStats;
}

UnitGradeStatsVec loadGradeStats(pqxx::transaction_base& txn, TId sampleId)
{
    const auto rows = txn.exec(
        "SELECT "
            "st." + sql::col::UNIT_ID + " as " + sql::col::UNIT_ID + ", " +
            gradeValueCount(txn, Grade::Value::Correct) + " as correct, " +
            gradeValueCount(txn, Grade::Value::Incorrect) + " as incorrect "
        "FROM " +
            sql::table::SAMPLE_TASK + " as st "
        "LEFT JOIN " +
            sql::table::GRADE + " "
        "USING "
            "(" + sql::col::GRADE_ID + ") "
        "WHERE " +
            sql::col::SAMPLE_ID + " = " + std::to_string(sampleId) + " "
        "GROUP BY "
            "st." + sql::col::UNIT_ID);

    UnitGradeStatsVec result;
    result.reserve(rows.size());
    for (const auto& row : rows) {
        result.emplace_back(makeUnitGradeStats(row));
    }
    return result;
}

} // maps::wiki::assessment::samples
