#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/secure_config.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/detect_panel/tests/fixture.h>

#include <maps/wikimap/mapspro/services/mrc/eye/lib/unit_test/include/frame.h>

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/frame_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/eye/recognition_gateway.h>

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

Fixture::Fixture()
{
    // The config content doesn't matter in the tests for now so anyone will fit.
    static std::once_flag onceFlag;
    std::call_once(onceFlag, SecureConfig::initialize, config());

    { // create devices
        auto txn = newTxn();

        devices = {
            {db::eye::MrcDeviceAttrs{"M1"}},
            {db::eye::MrcDeviceAttrs{"M2"}},
            {db::eye::MrcDeviceAttrs{"M3"}},
        };

        db::eye::DeviceGateway(*txn).upsertx(devices);
        txn->commit();
    }

    // create frames

    const db::TId firstDeviceId = devices[0].id();
    const db::TId secondDeviceId = devices[1].id();

    frames = {
        {firstDeviceId, identical, makeUrlContext(1, "1"), {284, 160}, time()},
        {firstDeviceId, identical, makeUrlContext(2, "2"), {284, 160}, time()},
        {firstDeviceId, identical, makeUrlContext(3, "3"), {284, 160}, time()},
        {firstDeviceId, identical, makeUrlContext(4, "4"), {284, 160}, time()},
        {firstDeviceId, identical, makeUrlContext(5, "5"), {284, 160}, time()},
        {firstDeviceId, identical, makeUrlContext(6, "6"), {284, 160}, time()},

        {secondDeviceId, upsideDown, makeUrlContext(7, "1_cw180"), {284, 160}, time()},
        {secondDeviceId, upsideDown, makeUrlContext(8, "2_cw180"), {284, 160}, time()},
        {secondDeviceId, upsideDown, makeUrlContext(9, "3_cw180"), {284, 160}, time()},
        {secondDeviceId, upsideDown, makeUrlContext(10, "4_cw180"), {284, 160}, time()},

        {secondDeviceId, onLeftSide, makeUrlContext(11, "1_cw90"), {160, 120}, time()},
        {secondDeviceId, onLeftSide, makeUrlContext(12, "2_cw90"), {160, 120}, time()},
        {secondDeviceId, onLeftSide, makeUrlContext(13, "3_cw90"), {160, 120}, time()},
        {secondDeviceId, onLeftSide, makeUrlContext(14, "4_cw90"), {160, 120}, time()},

        {secondDeviceId, upsideDown, makeUrlContext(15, "bad_path"), {284, 160}, time()},
        {secondDeviceId, upsideDown, makeUrlContext(16, "bad_path"), {284, 160}, time()},
    };

    frames[14].setDeleted(true);

    auto insert = [&](size_t begin, size_t end)
    {
        auto txn = newTxn();

        TArrayRef ref(frames.data() + begin, frames.data() + end);
        db::eye::FrameGateway(*txn).insertx(ref);

        txn->commit();
    };

    insert(0, 3);
    insert(3, 6);
    insert(6, 14);
    insert(14, 16);

    { // create recognitions
        auto txn = newTxn();

        const auto& frame = frames[15];

        db::eye::RecognitionGateway(*txn).insertx(
            db::eye::Recognition{
                frame.id(),
                frame.orientation(),
                db::eye::RecognitionType::DetectPanel,
                db::eye::RecognitionSource::Model,
                1,
                db::eye::DetectedPanel{common::ImageBox{0, 0, 100, 100}}
            }
        );

        txn->commit();
    }
}

Fixture::~Fixture() {
    playground().postgres().truncateTables();
}

db::TId Fixture::frameIdAt(size_t index) const
{
    return frames.at(index).id();
}

db::TIdSet Fixture::frameIdSetAt(std::initializer_list<size_t> indexes) const
{
    db::TIdSet ids;

    for (const auto index: indexes) {
        ids.insert(frameIdAt(index));
    }

    return ids;
}


db::TIds Fixture::frameIdsAt(std::initializer_list<size_t> indexes) const
{
    db::TIds ids;

    for (const auto index: indexes) {
        ids.push_back(frameIdAt(index));
    }

    return ids;
}

db::eye::Recognition Fixture::recognitionForFrameAt(size_t index) const
{
    return db::eye::RecognitionGateway(*newTxn()).loadOne(
        db::eye::table::Recognition::frameId == frameIdAt(index)
    );
}

size_t Fixture::countRecognitions() const
{
    return db::eye::RecognitionGateway(*newTxn()).count();
}

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