#include "common.h"
#include "eye/verification_source.h"
#include "fixture.h"

#include "../include/worker.h"
#include "toloka/platform.h"

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/verified_detection_missing_on_frame_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/frame_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/object_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/toloka/task_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/toloka_manager/include/detection_missing_on_frame.h>

#include <maps/libs/log8/include/log8.h>
#include <maps/libs/introspection/include/stream_output.h>

using namespace testing;

namespace maps::mrc::db::eye {

using maps::introspection::operator<<;

} //namespace maps::mrc::db::eye


namespace maps::mrc::eye::tests {

TEST_P(DetectionFixture, toloka_task)
{
    const size_t limit = 10;
    auto workerConfig = makeDetectionMissingOnFrameVerifierConfig();
    DetectionMissingOnFrameVerifier verifier(workerConfig);

    const auto source = GetParam();

    db::eye::VerifiedDetectionMissingOnFrame missing{
        source,
        detections[0].id(),
        frames[1].id()};

    {
        auto txn = newTxn();
        db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).insertx(missing);
        txn->commit();
    }

    size_t updatesNumber = verifier.processBatchInLoopMode(limit);
    EXPECT_EQ(updatesNumber, 1u);

    db::TId tolokaTaskId;
    {
        auto txn = newTxn();
        db::eye::VerifiedDetectionMissingOnFramesToTolokaTasks missingsToTasks =
            db::eye::VerifiedDetectionMissingOnFrameToTolokaTaskGateway(*txn)
                .load();
        EXPECT_EQ(missingsToTasks.size(), 1u);
        EXPECT_EQ(missingsToTasks[0].verifiedTaskId(), missing.id());

        tolokaTaskId = missingsToTasks[0].tolokaTaskId();

        db::toloka::Tasks tasks = db::toloka::TaskGateway(*txn).load(
            db::toloka::table::Task::id == tolokaTaskId);
        EXPECT_EQ(tasks.size(), 1u);
        auto expectedPlatform =
            source == db::eye::VerificationSource::Toloka
                ? db::toloka::Platform::Toloka
                : db::toloka::Platform::Yang;
        EXPECT_EQ(tasks[0].platform(), expectedPlatform);
        EXPECT_FALSE(tasks[0].outputValues().has_value());
    }

    {
        auto txn = newTxn();
        db::toloka::Tasks tasks = db::toloka::TaskGateway(*txn).load(
            db::toloka::table::Task::id == tolokaTaskId);

        toloka::DetectionMissingOnFrameOutput output{
            toloka::DetectionMissingOnFrameIsVisible::Yes,
            std::nullopt
        };
        std::stringstream ss;
        json::Builder builder(ss);
        builder << [&](json::ObjectBuilder b) { output.json(b); };

        tasks[0].setOutputValues(ss.str());

        db::toloka::TaskGateway(*txn).updatex(tasks);

        txn->commit();
    }

    updatesNumber = verifier.processBatchInLoopMode(limit);
    EXPECT_EQ(updatesNumber, 1u);

    {
        auto txn = newTxn();

        auto missings =
            db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).load();

        EXPECT_EQ(missings[0].detectionId(), detections[0].id());
        EXPECT_EQ(missings[0].frameId(), frames[1].id());
        EXPECT_EQ(missings[0].isVisible().value(), db::eye::VerifiedDetectionMissingOnFrameIsVisible::Yes);
    }
}

INSTANTIATE_TEST_SUITE_P(
    TolokaTasksTests,
    DetectionFixture,
    ValuesIn({
        db::eye::VerificationSource::Toloka,
        db::eye::VerificationSource::Yang
    })
);

} // namespace maps::mrc::eye::tests
