#include <maps/wikimap/mapspro/services/mrc/libs/classifiers/include/camera_deviation.h>

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

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

namespace maps::mrc::classifiers::tests {

namespace {
    class DummyFeature {
    public:
        DummyFeature() = default;

        DummyFeature(int sourceId, const std::string& timestamp)
            : sourceId_(sourceId)
            , timestamp_(chrono::parseSqlDateTime(timestamp))
        {
        }

        DummyFeature(int sourceId, const std::string& timestamp, db::CameraDeviation cameraDeviation)
            : sourceId_(sourceId)
            , timestamp_(chrono::parseSqlDateTime(timestamp))
            , cameraDeviation_(cameraDeviation)
        {
        }

        int sourceId() const {
            return sourceId_;
        }
        chrono::TimePoint timestamp() const {
            return timestamp_;
        }
        bool hasCameraDeviation() const {
            return cameraDeviation_.has_value();
        }
        db::CameraDeviation cameraDeviation() const {
            return cameraDeviation_.value_or(db::CameraDeviation::Front);
        }
        common::ImageOrientation orientation() const {
            return common::ImageOrientation();
        }
    private:
        int sourceId_;
        chrono::TimePoint timestamp_;
        std::optional<db::CameraDeviation> cameraDeviation_;
    };

    common::Blob loadFeatureImageData(const DummyFeature& /*feature*/) {
        static std::vector<uint8_t> data;
        if (0 == data.size()) {
            cv::imencode(".jpg", cv::Mat::zeros(200, 200, CV_8UC1), data);
        }
        return common::Blob(data.begin(), data.end());
    }
} // anonymous namespace

TEST(camera_deviation, test_have_same_camera_deviation) {
    std::vector<DummyFeature> sameCameraDeviation = {
        {0, "2000-01-01 00:00:00.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:01.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:02.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:03.000000+03", db::CameraDeviation::Front},
    };

    std::vector<DummyFeature> noCameraDeviation = {
        {0, "2000-01-01 00:00:00.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:01.000000+03"},
        {0, "2000-01-01 00:00:02.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:03.000000+03", db::CameraDeviation::Front},
    };

    std::vector<DummyFeature> diffCameraDeviation = {
        {0, "2000-01-01 00:00:00.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:01.000000+03", db::CameraDeviation::Front},
        {0, "2000-01-01 00:00:02.000000+03", db::CameraDeviation::Right},
        {0, "2000-01-01 00:00:03.000000+03", db::CameraDeviation::Front},
    };

    EXPECT_TRUE(haveSameCameraDeviation(sameCameraDeviation.begin(), sameCameraDeviation.end()));
    EXPECT_FALSE(haveSameCameraDeviation(noCameraDeviation.begin(), noCameraDeviation.end()));
    EXPECT_FALSE(haveSameCameraDeviation(diffCameraDeviation.begin(), diffCameraDeviation.end()));
}

TEST(camera_deviation, test_estimate_camera_deviation) {
    std::vector<DummyFeature> features(100);
    EXPECT_EQ((int16_t)estimateCameraDeviation(loadFeatureImageData, features.begin(), features.end()), 90);
}

} // namespace maps::mrc::common::tests
