#include <maps/wikimap/ugc/backoffice/src/assignments_cleaner/lib/expire.h>

#include <maps/wikimap/ugc/backoffice/src/lib/links.h>

#include <maps/wikimap/ugc/libs/common/constants.h>
#include <maps/wikimap/ugc/libs/test_helpers/db_fixture.h>
#include <maps/wikimap/ugc/libs/test_helpers/test_dbpools.h>

#include <maps/wikimap/mapspro/libs/query_builder/include/count_query.h>
#include <maps/wikimap/mapspro/libs/query_builder/include/insert_query.h>
#include <maps/wikimap/mapspro/libs/query_builder/include/select_query.h>

#include <maps/libs/chrono/include/time_point.h>

#include <library/cpp/testing/unittest/env.h>
#include <library/cpp/testing/unittest/registar.h>

namespace maps::wiki::ugc::backoffice::assignments_cleaner::tests {

namespace {

namespace qb = maps::wiki::query_builder;

void insertAssignment(
    pgpool3::Pool& pool,
    maps::chrono::TimePoint tp,
    AssignmentStatus status)
{
    auto txn = pool.masterWriteableTransaction();
    static int id = 1;
    Uid uid{11111};
    AssignmentId taskId{"task:" + std::to_string(id)};
    ++id;
    // Insert assignments
    maps::wiki::query_builder::InsertQuery(tables::ASSIGNMENT)
        .append(columns::UID, std::to_string(uid.value()))
        .appendQuoted(columns::TASK_ID, taskId.value())
        .appendQuoted(columns::STATUS, std::string{toString(status)})
        .append(columns::METADATA_ID, "3")
        .appendQuoted(columns::CREATED_AT, maps::chrono::formatSqlDateTime(tp))
        .appendQuoted(columns::UPDATED_AT, maps::chrono::formatSqlDateTime(tp))
    .exec(*txn);
    txn->commit();
}

} // namespace

Y_UNIT_TEST_SUITE(test_expire_assignments)
{

Y_UNIT_TEST(delete_assignments)
{
    ugc::tests::TestDbPools dbPools;

    const auto futureTimePoint = maps::chrono::parseIsoDateTime("2199-02-01 12:00:00+00:00");
    for (const AssignmentStatus status : {
        AssignmentStatus::Expired,
        AssignmentStatus::Active,
        AssignmentStatus::Skipped,
        AssignmentStatus::Done}
    ) {
        insertAssignment(
            dbPools.pool(),
            maps::chrono::parseIsoDateTime("2001-02-01 12:00:00+00:00"),
            status
        );
        insertAssignment(
            dbPools.pool(),
            futureTimePoint,
            status
        );
    }

    auto txn = dbPools.pool().masterWriteableTransaction();
    UNIT_ASSERT_VALUES_EQUAL(qb::CountQuery(tables::ASSIGNMENT).exec(*txn), 8);
    deleteAssignments(*txn);
    // deleted skipped and expired assignments that expire 2001-02-01
    const auto& rows = qb::SelectQuery(tables::ASSIGNMENT).exec(*txn);
    UNIT_ASSERT_VALUES_EQUAL(rows.size(), 6);
    for (const auto& row : rows) {
        const auto& status = maps::enum_io::fromString<AssignmentStatus>(row[columns::STATUS].as<std::string>());
        UNIT_ASSERT(
            status == AssignmentStatus::Done ||
            status == AssignmentStatus::Active ||
            maps::chrono::parseSqlDateTime(row[columns::UPDATED_AT].as<std::string>()) == futureTimePoint
        );
    }
}

Y_UNIT_TEST(expire_assignments)
{
    ugc::tests::TestDbPools dbPools;

    const auto futureTimePoint = maps::chrono::parseIsoDateTime("2199-02-01 12:00:00+00:00");
    const auto pastTimePoint = maps::chrono::parseIsoDateTime("2001-02-01 12:00:00+00:00");
    for (const AssignmentStatus status :
        {
            AssignmentStatus::Active,
            AssignmentStatus::Skipped,
            AssignmentStatus::Done
        }
    ) {
        insertAssignment(
            dbPools.pool(),
            pastTimePoint,
            status
        );
        insertAssignment(
            dbPools.pool(),
            futureTimePoint,
            status
        );
    }

    auto txn = dbPools.pool().masterWriteableTransaction();
    UNIT_ASSERT_VALUES_EQUAL(
        qb::CountQuery(
            tables::ASSIGNMENT,
            qb::WhereConditions()
                .appendQuoted(columns::STATUS, std::string{toString(AssignmentStatus::Expired)})
        ).exec(*txn),
        0
    );
    expireAssignments(*txn);
    // mark old active assignments as expired
    const auto& rows = qb::SelectQuery(
        tables::ASSIGNMENT,
        qb::WhereConditions()
            .appendQuoted(columns::STATUS, std::string{toString(AssignmentStatus::Expired)})
    ).exec(*txn);
    UNIT_ASSERT_VALUES_EQUAL(rows.size(), 1);
}

}

} // namespace maps::wiki::ugc::backoffice::assignments_cleaner::tests
