#include "toloka/platform.h"
#include <maps/wikimap/mapspro/services/mrc/eye/lib/import_detection/tests/fixture.h>

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

using namespace maps::mrc::db::toloka;
using namespace maps::mrc::db::eye;
using namespace maps::mrc::db;

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

namespace {

db::Feature createFeature(common::ImageOrientation orientation) {
    return db::Feature{"0",
                       geolib3::Point2{0, 0},
                       geolib3::Heading{0},
                       "2016-01-01 00:00:01+03",
                       mds::Key{"group", "path"},
                       db::Dataset::Agents}
        .setSize(6, 9)
        .setAutomaticShouldBePublished(true)
        .setIsPublished(true)
        .setOrientation(orientation);
}

db::TrafficLight createTrafficLight() {
    return sql_chemistry::GatewayAccess<TrafficLight>::construct();
}

db::Sign createSign(traffic_signs::TrafficSign type) {
    return sql_chemistry::GatewayAccess<Sign>::construct()
        .setType(type);
}

db::HouseNumber createHouseNumber(const std::string& number) {
    return sql_chemistry::GatewayAccess<HouseNumber>::construct()
        .setNumber(number);
}

} // namespace

Fixture::Fixture() {
    {
        features = {
            createFeature(common::ImageOrientation(common::Rotation::CW_0)),
            createFeature(common::ImageOrientation(common::Rotation::CW_0)),
            createFeature(common::ImageOrientation(common::Rotation::CW_0)),
            createFeature(common::ImageOrientation(common::Rotation::CW_180)),
            createFeature(common::ImageOrientation(common::Rotation::CW_90))
        };

        auto insert = [&](size_t begin, size_t end) {
            ASSERT(begin <= end && end <= features.size());
            auto txn = txnHandle();
            TArrayRef ref(features.data() + begin, features.data() + end);
            db::FeatureGateway(*txn).insert(ref);
            db::updateFeaturesTransaction(ref, *txn);

            db::TId txnId = sql_chemistry::SystemInformation(*txn).getCurrentTransactionId();

            txn->commit();

            return txnId;
        };

        db::TId txnId = insert(0, 4);

        auto txn = txnHandle();
        db::MetadataGateway(*txn).upsertByKey("signs_detector.last_transaction_id", txnId);
        txn->commit();

        insert(4, 5);
    }

    {
        auto txn = txnHandle();

        trafficLights = {
            createTrafficLight(),
            createTrafficLight(),
        };

        TrafficLightGateway(*txn).insert(trafficLights);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        trafficLightFeatures = {
            db::TrafficLightFeature(features[0].id(), 10, 10, 20, 20)
                .setTrafficLightId(trafficLights[0].id()),
            db::TrafficLightFeature(features[0].id(), 20, 20, 30, 30)
                .setTrafficLightId(trafficLights[1].id()),
            db::TrafficLightFeature(features[1].id(), 30, 30, 40, 40)
                .setTrafficLightId(trafficLights[1].id()),
        };

        TrafficLightFeatureGateway(*txn).insert(trafficLightFeatures);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        signs = {
            createSign(traffic_signs::TrafficSign::PriorityPriorityRoad),
            createSign(traffic_signs::TrafficSign::PriorityStop),
            createSign(traffic_signs::TrafficSign::RoadMarkingLaneDirectionF),
        };

        SignGateway(*txn).insert(signs);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        signFeatures = {
            db::SignFeature(features[0].id(), 10, 10, 20, 20)
                .setSignId(signs[0].id()),
            db::SignFeature(features[2].id(), 40, 40, 50, 50)
                .setSignId(signs[1].id()),
            db::SignFeature(features[0].id(), 60, 60, 70, 70)
                .setSignId(signs[2].id()),
        };

        SignFeatureGateway(*txn).insert(signFeatures);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        houseNumbers = {
            createHouseNumber("1"),
            createHouseNumber("2"),
        };

        HouseNumberGateway(*txn).insert(houseNumbers);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        houseNumberFeatures = {
            db::HouseNumberFeature(features[0].id(), 10, 10, 20, 20)
                .setHouseNumberId(houseNumbers[0].id()),
            db::HouseNumberFeature(features[1].id(), 40, 40, 50, 50)
                .setHouseNumberId(houseNumbers[1].id()),
        };

        HouseNumberFeatureGateway(*txn).insert(houseNumberFeatures);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        devices = {
            Device(MrcDeviceAttrs{"M1"}),
            Device(MrcDeviceAttrs{"M2"}),
            Device(MrcDeviceAttrs{"M3"}),
        };
        DeviceGateway(*txn).insertx(devices);

        txn->commit();
    }

    {
        frames = {
            {
                devices[0].id(),
                common::ImageOrientation(common::Rotation::CW_0),
                MrcUrlContext{1, "1", "1"},
                {1280, 720},
                chrono::parseSqlDateTime("2017-05-06 07:01:15+03")
            },
            {
                devices[1].id(),
                common::ImageOrientation(common::Rotation::CW_0),
                MrcUrlContext{4, "4", "4"},
                {1280, 720},
                chrono::parseSqlDateTime("2016-04-02 05:57:11+03")
            },
            {
                devices[1].id(),
                common::ImageOrientation(common::Rotation::CW_0),
                MrcUrlContext{4, "4", "4"},
                {1280, 720},
                chrono::parseSqlDateTime("2016-04-02 05:57:56+03")
            },
            {
                devices[1].id(),
                common::ImageOrientation(common::Rotation::CW_90),
                MrcUrlContext{4, "6", "6"},
                {1280, 720},
                chrono::parseSqlDateTime("2016-04-02 05:58:11+03")
            },
            {
                devices[1].id(),
                common::ImageOrientation(common::Rotation::CW_180),
                MrcUrlContext{4, "7", "7"},
                {1280, 720},
                chrono::parseSqlDateTime("2016-04-02 05:58:11+03")
            },
        };

        auto insert = [&](size_t indx) {
            auto txn = txnHandle();
            db::eye::FrameGateway(*txn).insertx(frames[indx]);
            txn->commit();
        };

        insert(0);
        insert(1);
        insert(2);
        insert(3);
        insert(4);
    }

    {
        auto txn = txnHandle();

        featureToFrameVec = {
            {features[0].id(), frames[0].id()},
            {features[1].id(), frames[1].id()},
            {features[2].id(), frames[2].id()},
            {features[3].id(), frames[3].id()},
            {features[4].id(), frames[4].id()},
        };

        FeatureToFrameGateway(*txn).insert(featureToFrameVec);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        recognitions = {
            {
                frames[0].id(),
                common::ImageOrientation(common::Rotation::CW_0),
                RecognitionType::DetectTrafficLight,
                RecognitionSource::Toloka,
                1
            },
            {
                frames[1].id(),
                common::ImageOrientation(common::Rotation::CW_90),
                RecognitionType::DetectSign,
                RecognitionSource::Model,
                2
            },
            {
                frames[2].id(),
                common::ImageOrientation(common::Rotation::CW_180),
                RecognitionType::DetectTrafficLight,
                RecognitionSource::Toloka,
                1
            },
            {
                frames[2].id(),
                common::ImageOrientation(common::Rotation::CW_0),
                RecognitionType::DetectHouseNumber,
                RecognitionSource::Model,
                2
            },
        };
        RecognitionGateway(*txn).insertx(recognitions);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        tasks = {
            {
                Task(toloka::Platform::Toloka)
                      .setType(TaskType::TrafficLightDetection)
                      .setStatus(TaskStatus::Finished)
                      .setInputValues(R"({"source": "https://yandex.ru/image-1"})")
                      .setOutputValues(R"({"polygons": [[[10, 10], [20, 20]]]})")
            },
        };
        TaskGateway(*txn).insertx(tasks);

        txn->commit();
    }

    {
        auto txn = txnHandle();

        recognitionTasks = {
            {
                recognitions[0].id(),
                tasks[0].id()
            }
        };
        RecognitionTaskGateway(*txn).insertx(recognitionTasks);

        txn->commit();
    }
}

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