#include <maps/wikimap/mapspro/services/mrc/libs/db/tests/eye/common.h>

#include <library/cpp/testing/gtest/gtest.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/common/include/exception.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/verified_detection_missing_on_frame_gateway.h>
#include <yandex/maps/mrc/unittest/unittest_config.h>

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

TEST_F(DetectionFixture, make_verified_detection_missing_on_frame)
{
    VerifiedDetectionMissingOnFrames items{
        {
            VerificationSource::Toloka,
            detections[0].id(), frames[0].id()
        },
        {
            VerificationSource::Toloka,
            detections[1].id(), frames[1].id()
        }
    };

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

    {
        auto txn = txnHandle();

        VerifiedDetectionMissingOnFrame loadedItem1
            = db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).loadById(items[0].id());
        EXPECT_EQ(loadedItem1.id(), items[0].id());
        EXPECT_EQ(loadedItem1.detectionId(), detections[0].id());
        EXPECT_EQ(loadedItem1.frameId(), frames[0].id());
        EXPECT_EQ(loadedItem1.isVisible(), std::nullopt);
        EXPECT_EQ(loadedItem1.missingReason(), std::nullopt);

        VerifiedDetectionMissingOnFrame loadedItem2
            = db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).loadById(items[1].id());
        EXPECT_EQ(loadedItem2.id(), items[1].id());
        EXPECT_EQ(loadedItem2.detectionId(), detections[1].id());
        EXPECT_EQ(loadedItem2.frameId(), frames[1].id());
        EXPECT_EQ(loadedItem2.isVisible(), std::nullopt);
        EXPECT_EQ(loadedItem2.missingReason(), std::nullopt);
    }

    items[0].setIsVisible(VerifiedDetectionMissingOnFrameIsVisible::Yes);
    items[1].setIsVisible(VerifiedDetectionMissingOnFrameIsVisible::No);
    items[1].setMissingReason(VerifiedDetectionMissingOnFrameMissingReason::Missing);

    {
        auto txn = txnHandle();
        db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).updatex(items);
        txn->commit();
    }

    {
        auto txn = txnHandle();

        VerifiedDetectionMissingOnFrame loadedItem1
            = db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).loadById(items[0].id());
        EXPECT_EQ(loadedItem1.id(), items[0].id());
        EXPECT_EQ(loadedItem1.detectionId(), detections[0].id());
        EXPECT_EQ(loadedItem1.frameId(), frames[0].id());
        EXPECT_EQ(loadedItem1.isVisible(), VerifiedDetectionMissingOnFrameIsVisible::Yes);
        EXPECT_EQ(loadedItem1.missingReason(), std::nullopt);

        VerifiedDetectionMissingOnFrame loadedItem2
            = db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).loadById(items[1].id());
        EXPECT_EQ(loadedItem2.id(), items[1].id());
        EXPECT_EQ(loadedItem2.detectionId(), detections[1].id());
        EXPECT_EQ(loadedItem2.frameId(), frames[1].id());
        EXPECT_EQ(loadedItem2.isVisible(), VerifiedDetectionMissingOnFrameIsVisible::No);
        EXPECT_EQ(loadedItem2.missingReason(), VerifiedDetectionMissingOnFrameMissingReason::Missing);
    }

    toloka::Tasks tasks = {
        toloka::Task(toloka::Platform::Toloka)
            .setType(toloka::TaskType::DetectionMissingOnFrame)
            .setStatus(toloka::TaskStatus::New)
            .setInputValues("input-values-1")
            .setOverlap(3)
            .setCreatedAt(chrono::parseSqlDateTime("2017-01-01 00:00:00+03")),
        toloka::Task(toloka::Platform::Toloka)
            .setType(toloka::TaskType::DetectionMissingOnFrame)
            .setStatus(toloka::TaskStatus::New)
            .setInputValues("input-values-2")
            .setOverlap(3)
            .setCreatedAt(chrono::parseSqlDateTime("2017-01-01 00:00:00+03")),
    };

    {
        auto txn = txnHandle();
        db::toloka::TaskGateway(*txn).insertx(tasks);
        txn->commit();
    }

    VerifiedDetectionMissingOnFramesToTolokaTasks itemsToTolokas{
        {items[0].id(), tasks[0].id()},
        {items[1].id(), tasks[1].id()},
    };

    {
        auto txn = txnHandle();
        db::eye::VerifiedDetectionMissingOnFrameToTolokaTaskGateway(*txn).insert(itemsToTolokas);
        txn->commit();
    }
}

TEST_F(DetectionFixture, unique_verified_detection_missing_on_frame)
{
    VerifiedDetectionMissingOnFrame item1(
        VerificationSource::Toloka,
        detections[0].id(), frames[0].id()
    );

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

    VerifiedDetectionMissingOnFrame item2(
        VerificationSource::Toloka,
        detections[0].id(), frames[0].id()
    );

    {
        auto txn = txnHandle();
        EXPECT_THROW(
            db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).insertx(item2),
            maps::sql_chemistry::UniqueViolationError
        );
    }
}

TEST_F(DetectionFixture, set_result_verified_detection_missing_on_frame)
{
    VerifiedDetectionMissingOnFrame item(
        VerificationSource::Toloka,
        detections[0].id(), frames[0].id()
    );

    item.setIsVisible(VerifiedDetectionMissingOnFrameIsVisible::Yes);

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

    {
        auto txn = txnHandle();
        VerifiedDetectionMissingOnFrame loadedItem
            = db::eye::VerifiedDetectionMissingOnFrameGateway(*txn).loadById(item.id());

        EXPECT_EQ(loadedItem.id(), item.id());
        EXPECT_EQ(loadedItem.detectionId(), detections[0].id());
        EXPECT_EQ(loadedItem.frameId(), frames[0].id());
        EXPECT_EQ(loadedItem.isVisible(), VerifiedDetectionMissingOnFrameIsVisible::Yes);
    }
}

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