#include "fixture.h"

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/feature_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/video_gateway.h>

#include <library/cpp/testing/gtest/gtest.h>

namespace maps::mrc::db {
using introspection::operator==;
} // namespace maps::mrc::db

namespace maps::mrc::db::tests {
using namespace ::testing;

namespace {

const std::string SOURCE_ID = "source";
mds::Key MDS_KEY{"4436", "123/video/1.mp4"};
const std::string TEST_USER_ID = "123456";

} // namespace

TEST_F(Fixture, test_video) {
    auto txn = txnHandle();

    VideoGateway gtw(*txn);

    Video video(
        Dataset::TaxiSignalQ2,
        SOURCE_ID,
        chrono::parseSqlDateTime("2019-06-04 09:00:00+03"),
        3.14,
        MDS_KEY);

    gtw.upsert(video);
    EXPECT_TRUE(video.id());

    auto loadedVideo = gtw.loadById(video.id());
    EXPECT_EQ(video, loadedVideo);
}

TEST_F(Fixture, test_frame_to_video) {
    auto txn = txnHandle();

    auto features = Features{
        Feature(
            SOURCE_ID,
            geolib3::Point2{1.0, 1.0},
            geolib3::Heading{10},
            "2021-09-23 12:00:00+03",
            mds::Key{"4436", "feature_1.jpg"},
            Dataset::TaxiSignalQ2),
        Feature(
            SOURCE_ID,
            geolib3::Point2{2.0, 2.0},
            geolib3::Heading{10},
            "2021-09-23 12:00:01+03",
            mds::Key{"4436", "feature_2.jpg"},
            Dataset::TaxiSignalQ2),
    };

    auto video = Video(
        Dataset::TaxiSignalQ2,
        SOURCE_ID,
        chrono::parseSqlDateTime("2019-06-04 09:00:00+03"),
        3.14,
        MDS_KEY);
    video.setEventId(12345);

    {
        auto txn = txnHandle();
        FeatureGateway{*txn}.insert(features);
        VideoGateway{*txn}.insert(video);
        txn->commit();
    }

    auto framesToVideo = FrameToVideos{
        FrameToVideo(features[0].id(), video.id(), 0.),
        FrameToVideo(features[1].id(), video.id(), 1.25)
    };

    {
        auto txn = txnHandle();
        FrameToVideoGateway{*txn}.insert(framesToVideo);
        txn->commit();
    }

    {
        auto txn = txnHandle();
        auto loadedFramesToVideo = FrameToVideoGateway{*txn}
            .load(table::FrameToVideo::videoId == video.id(),
                  sql_chemistry::orderBy(table::FrameToVideo::id));
        EXPECT_EQ(loadedFramesToVideo, framesToVideo);
    }
}

TEST_F(Fixture, test_video_unique_event_id) {
    auto now = chrono::TimePoint::clock::now();
    {
        auto video = Video(Dataset::TaxiSignalQ2, SOURCE_ID, now, 3.14, MDS_KEY);
        video.setEventId(1);
        auto txn = txnHandle();
        VideoGateway{*txn}.insert(video);
        txn->commit();
    }

    // Can't create event with the same dataset and eventId
    {
        auto video = Video(Dataset::TaxiSignalQ2, SOURCE_ID, now, 3.14, MDS_KEY);
        video.setEventId(1);
        auto txn = txnHandle();
        EXPECT_THROW(VideoGateway{*txn}.insert(video), sql_chemistry::UniqueViolationError);
    }

    // It's ok to have same event_id but from a different dataset
    {
        auto video = Video(Dataset::NexarDashcams, SOURCE_ID, now, 3.14, MDS_KEY);
        video.setEventId(1);
        auto txn = txnHandle();
        VideoGateway{*txn}.insert(video);
        txn->commit();
    }

    // It's ok to have multiple records without event_id from the same dataset
    {
        auto videos = Videos{
            Video(Dataset::TaxiSignalQ2, SOURCE_ID, now, 3.14, MDS_KEY),
            Video(Dataset::TaxiSignalQ2, SOURCE_ID, now + std::chrono::seconds(10), 3.15, MDS_KEY)
        };

        auto txn = txnHandle();
        VideoGateway{*txn}.insert(videos);
        txn->commit();
    }
}

TEST_F(Fixture, test_video_unique_event_hash) {
    constexpr std::size_t EVENT_HASH = 100500;
    auto now = chrono::TimePoint::clock::now();
    {
        auto video = Video(Dataset::TaxiSignalQ2, SOURCE_ID, now, 3.14, MDS_KEY);
        video.setEventHash(EVENT_HASH);
        auto txn = txnHandle();
        VideoGateway{*txn}.insert(video);
        txn->commit();
    }

    // Can't create event with the same eventHash
    {
        auto video = Video(Dataset::TaxiSignalQ2, SOURCE_ID, now + std::chrono::seconds(10), 3.15, MDS_KEY);
        video.setEventHash(EVENT_HASH);
        auto txn = txnHandle();
        EXPECT_THROW(VideoGateway{*txn}.insert(video), sql_chemistry::UniqueViolationError);
    }
}

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