#include "construct.h"
#include "fixture.h"

#include <library/cpp/testing/gtest/gtest.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/feature_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/house_number_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/panorama_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/walk_object_gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/unittest/include/yandex/maps/mrc/unittest/database_fixture.h>
#include <maps/wikimap/mapspro/services/mrc/libs/unittest/include/yandex/maps/mrc/unittest/log_disabling_fixture.h>
#include <maps/libs/geolib/include/units_literals.h>

namespace maps::mrc::db::tests {
using namespace ::testing;
using geolib3::Point2;
using geolib3::Heading;

namespace {

TId insertAssigment(maps::pgpool3::TransactionHandle txn) {
    const geolib3::MultiPolygon2 TEST_HULL{
        {geolib3::Polygon2{
            geolib3::PointsVector{{0, 0}, {0, 1}, {1, 1}, {0, 0}}},
            geolib3::Polygon2{
                geolib3::PointsVector{{0, 0}, {-1, 0}, {-1, -1}, {0, 0}}}}};

    ugc::Task task{};
    task.setStatus(ugc::TaskStatus::New)
        .setDuration(std::chrono::hours(24) * 80)
        .setDistanceInMeters(100000)
        .setGeodeticHull(TEST_HULL);
    ugc::TaskGateway{ *txn }.insert(task);

    ugc::Assignment assignment = task.assignTo("UserID");
    ugc::TaskGateway{ *txn }.update(task);
    ugc::AssignmentGateway{ *txn }.insert(assignment);
    TId assignmentId = assignment.id();

    txn->commit();

    return assignmentId;
}
}// namespace

TEST_F(Fixture, test_house_number) {

    const std::vector<HouseNumber> DATA{
        { "1", Point2{ 51.0, 51.0 } },
        { "2", Point2{ 52.0, 52.0 } },
        { "3", Point2{ 53.0, 53.0 } },
        { "4", Point2{ 54.0, 54.0 } },
        { "5", Point2{ 55.0, 55.0 } },
    };
    TIds ids;
    size_t count = 0;

    HouseNumbers hnss = DATA;
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        gtw.insert(hnss);
        for (size_t i = 0; i < hnss.size(); i++) {
            ids.push_back(hnss[i].id());
        }

        HouseNumber anotherHNS{ "6 other", Point2{ 60., 60.0 } };
        gtw.insert(anotherHNS);
        hnss.push_back(anotherHNS);
        ids.push_back(anotherHNS.id());
        txn->commit();
        count = hnss.size();
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };

        EXPECT_EQ(gtw.loadByIds(ids).size(), count);

        for (size_t i = 0; i < hnss.size(); ++i) {
            const HouseNumber &hns = gtw.loadById(ids[i]);
            EXPECT_EQ(hns, hnss[i]);
            EXPECT_FALSE(hns.number().empty());
        }

        geolib3::BoundingBox bbox{ { 50., 50. },{ 56., 56. } };
        HouseNumbers hnssIntersects = gtw.load(table::HouseNumber::position.intersects(bbox));
        EXPECT_EQ(hnssIntersects.size(), DATA.size());

        HouseNumbers hnssNumberOther = gtw.load(table::HouseNumber::number.like("6 other"));
        EXPECT_EQ(hnssNumberOther.size(), 1u);
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        HouseNumber hns = gtw.loadById(ids.back());
        hns.setNumber("new");
        hns.setMercatorPos(Point2{ 57., 57. });
        gtw.update(hns);

        HouseNumber loaded = gtw.loadById(ids.back());
        EXPECT_EQ(loaded, hns);
        txn->commit();
    }

    TId id;
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };

        EXPECT_EQ(gtw.loadIds().size(), ids.size());

        // remove all signs but the last one
        id = ids.back();
        ids.pop_back();
        gtw.removeByIds(ids);
        txn->commit();
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        TIds remainedIds = gtw.loadIds();
        EXPECT_EQ(remainedIds.size(), 1u);
        EXPECT_EQ(remainedIds.front(), id);
    }
}

TEST_F(Fixture, test_house_number_features) {

    const std::vector<HouseNumber> HNS_DATA{
        { "1", Point2{ 51.0, 51.0 } },
        { "2", Point2{ 52.0, 52.0 } },
    };

    HouseNumbers hnssVector = HNS_DATA;
    HouseNumber  hnsSingle("3", Point2{ 53.0, 53.0 });
    HouseNumber  hnsForBoth("4", Point2{ 54.0, 54.0 });
    { // create house number signs
        maps::pgpool3::TransactionHandle txn = txnHandle();

        HouseNumberGateway gtw{ *txn };
        gtw.insert(hnssVector);
        gtw.insert(hnsSingle);
        gtw.insert(hnsForBoth);

        txn->commit();
    }

    auto feature1 = Feature{"src1",
                            Point2{1.0, 1.0},
                            Heading{10.0},
                            "2019-05-29 11:58:00+03",
                            mds::Key{"4510", "photo1.jpg"},
                            Dataset::Agents}
                        .setSize({6, 9})
                        .setAutomaticShouldBePublished(true)
                        .setIsPublished(true);
    auto feature2 = Feature{"src2",
                            Point2{2.0, 2.0},
                            Heading{20.0},
                            "2019-05-29 11:58:01+03",
                            mds::Key{"4510", "photo2.jpg"},
                            Dataset::Agents}
                        .setSize({6, 9})
                        .setAutomaticShouldBePublished(true)
                        .setIsPublished(true);

    { // create features
        maps::pgpool3::TransactionHandle txn = txnHandle();

        FeatureGateway gateway(*txn);
        gateway.insert(feature1);
        gateway.insert(feature2);

        txn->commit();
    }

    HouseNumberFeatures hnsfsVector;
    for (size_t i = 0; i < hnssVector.size(); i++) {
        hnsfsVector.push_back(HouseNumberFeature(feature1.id(), 1 + i, 1 + i, 2 + i, 2 + i).setHouseNumberId(hnssVector[i].id()));
    }

    HouseNumberFeature hnsfSingle(feature2.id(), 5, 5, 6, 6);
    hnsfSingle.setHouseNumberId(hnsSingle.id());

    HouseNumberFeatures hnsfsForBoth;
    hnsfsForBoth.push_back(HouseNumberFeature(feature1.id(), 6, 6, 7, 7).setHouseNumberId(hnsForBoth.id()));
    hnsfsForBoth.push_back(HouseNumberFeature(feature2.id(), 7, 7, 8, 8).setHouseNumberId(hnsForBoth.id()));

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();

        HouseNumberFeatureGateway gateway(*txn);
        gateway.insert(hnsfsVector);
        gateway.insert(hnsfSingle);
        gateway.insert(hnsfsForBoth);

        txn->commit();
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberFeatureGateway gtw{ *txn };

        HouseNumberFeatures hnsfsForBothTest = gtw.load(table::HouseNumberFeature::houseNumberId == hnsForBoth.id());
        EXPECT_EQ(hnsfsForBothTest.size(), hnsfsForBoth.size());

        HouseNumberFeatures hnsfsFeature1Test = gtw.load(table::HouseNumberFeature::featureId == feature1.id());
        EXPECT_EQ(hnsfsFeature1Test.size(), hnsfsVector.size() + 1);

        HouseNumberFeatures hnsfsFeature2Test = gtw.load(table::HouseNumberFeature::featureId == feature2.id());
        EXPECT_EQ(hnsfsFeature2Test.size(), 1u + 1u);
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        gtw.removeById(hnsForBoth.id());
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberFeatureGateway gtw{ *txn };
        HouseNumberFeatures remained = gtw.load();
        EXPECT_EQ(remained.size(), hnsfsVector.size() + 1);
    }
}

TEST_F(Fixture, test_house_number_panoramas) {

    const std::vector<HouseNumber> HNS_DATA{
        { "1", Point2{ 51.0, 51.0 } },
        { "2", Point2{ 52.0, 52.0 } },
    };

    HouseNumbers hnssVector = HNS_DATA;
    HouseNumber  hnsSingle("3", Point2{ 53.0, 53.0 });
    HouseNumber  hnsForBoth("4", Point2{ 54.0, 54.0 });
    { // create house number signs
        maps::pgpool3::TransactionHandle txn = txnHandle();

        HouseNumberGateway gtw{ *txn };
        gtw.insert(hnssVector);
        gtw.insert(hnsSingle);
        gtw.insert(hnsForBoth);

        txn->commit();
    }

    using namespace std::literals;
    Panorama panorama1{"mds_key_1", "src_key_1", chrono::TimePoint{1s}, 1, 1,
                       Point2{1.0, 1.0}, 1.0, 1.0, 1.0, 256, 256, 512, 512, 0};
    Panorama panorama2{"mds_key_2", "src_key_2", chrono::TimePoint{2s}, 2, 2,
                       Point2{2.0, 2.0}, 2.0, 2.0, 2.0, 256, 256, 512, 512, 0};

    { // create panoramas
        maps::pgpool3::TransactionHandle txn = txnHandle();

        PanoramaGateway gateway(*txn);
        gateway.insert(panorama1);
        gateway.insert(panorama2);

        txn->commit();
    }

    HouseNumberPanoramas hnspsVector;
    for (size_t i = 0; i < hnssVector.size(); i++) {
        hnspsVector.push_back(
            HouseNumberPanorama(panorama1.panoramaId(), 1 + i, 1 + i, 2 + i,
                                2 + i)
                .setHouseNumberId(hnssVector[i].id()));
    }

    HouseNumberPanorama hnspsingle(panorama2.panoramaId(), 5, 5, 6, 6);
    hnspsingle.setHouseNumberId(hnsSingle.id());

    HouseNumberPanoramas hnspsForBoth;
    hnspsForBoth.push_back(
        HouseNumberPanorama(panorama1.panoramaId(), 6, 6, 7, 7)
            .setHouseNumberId(hnsForBoth.id()));
    hnspsForBoth.push_back(
        HouseNumberPanorama(panorama2.panoramaId(), 7, 7, 8, 8)
            .setHouseNumberId(hnsForBoth.id()));

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();

        HouseNumberPanoramaGateway gateway(*txn);
        gateway.insert(hnspsVector);
        gateway.insert(hnspsingle);
        gateway.insert(hnspsForBoth);

        txn->commit();
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberPanoramaGateway gtw{ *txn };

        HouseNumberPanoramas hnspsForBothTest = gtw.load(table::HouseNumberPanorama::houseNumberId == hnsForBoth.id());
        EXPECT_EQ(hnspsForBothTest.size(), hnspsForBoth.size());

        HouseNumberPanoramas hnspsPanorama1Test = gtw.load(table::HouseNumberPanorama::panoramaId == panorama1.panoramaId());
        EXPECT_EQ(hnspsPanorama1Test.size(), hnspsVector.size() + 1);

        HouseNumberPanoramas hnspsPanorama2Test = gtw.load(table::HouseNumberPanorama::panoramaId == panorama2.panoramaId());
        EXPECT_EQ(hnspsPanorama2Test.size(), 1u + 1u);
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        gtw.removeById(hnsForBoth.id());
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberPanoramaGateway gtw{ *txn };
        HouseNumberPanoramas remained = gtw.load();
        EXPECT_EQ(remained.size(), hnspsVector.size() + 1);
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        PanoramaGateway gtw{ *txn };
        gtw.removeById(panorama1.panoramaId());
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberPanoramaGateway gtw{ *txn };
        HouseNumberPanoramas remained = gtw.load();
        EXPECT_EQ(remained.size(), 1u);
    }
}

TEST_F(Fixture, test_linked_house_numbers_ext) {
    HouseNumbers hnssVector = {
        { "base", Point2{ 51.0, 51.0 } },
        { "ride", Point2{ 52.0, 52.0 } },
        { "assignment", Point2{ 53.0, 53.0 } },
        { "walk", Point2{ 54.0, 54.0 } },
        { "panorama", Point2{ 55.0, 55.0 } }
    };
    constexpr size_t houseNumberBaseIdx = 0;
    constexpr size_t houseNumberRideIdx = 1;
    constexpr size_t houseNumberAssignmentIdx = 2;
    constexpr size_t houseNumberWalkIdx = 3;
    constexpr size_t houseNumberPanoIdx = 4;


    { // create house number signs
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        gtw.insert(hnssVector);
        txn->commit();
    }

    HouseNumberFeatures houseNumberFeatures;
    HouseNumberPanoramas houseNumberPanoramas;

    auto features = Features{Feature{"base",
                                     Point2{1.0, 1.0},
                                     Heading{10.0},
                                     "2019-06-25 09:50:00+03",
                                     mds::Key{"4510", "photo1.jpg"},
                                     Dataset::Agents}
                                 .setSize({6, 9})
                                 .setAutomaticShouldBePublished(true)
                                 .setIsPublished(true),
                             Feature{"base",
                                     Point2{2.0, 2.0},
                                     Heading{10.0},
                                     "2019-06-25 09:50:00+03",
                                     mds::Key{"4510", "photo2.jpg"},
                                     Dataset::Agents}
                                 .setSize({6, 9})
                                 .setAutomaticShouldBePublished(true)
                                 .setIsPublished(true)};
    { // create features
        maps::pgpool3::TransactionHandle txn = txnHandle();

        FeatureGateway gateway(*txn);
        gateway.insert(features);
        txn->commit();
        for (size_t i = 0; i < features.size(); i++) {
            houseNumberFeatures.push_back(
                HouseNumberFeature(features[i].id(), 1 + i, 1 + i, 2 + i, 2 + i)
                .setHouseNumberId(hnssVector[houseNumberBaseIdx].id())
            );
        }
    }

    auto ridePhotos = Features{Feature("ride",
                                       Point2{1.0, 1.0},
                                       Heading{10.0},
                                       "2019-06-25 09:50:00+03",
                                       mds::Key{"4510", "ride_photo1.jpg"},
                                       Dataset::Agents)
                                   .setSize({6, 9})
                                   .setAutomaticShouldBePublished(true)
                                   .setIsPublished(true)
                                   .setUserId("userID"),
                               Feature("ride",
                                       Point2{2.0, 2.0},
                                       Heading{10.0},
                                       "2019-06-25 09:50:00+03",
                                       mds::Key{"4510", "ride_photo2.jpg"},
                                       Dataset::Agents)
                                   .setSize({6, 9})
                                   .setAutomaticShouldBePublished(true)
                                   .setIsPublished(true)
                                   .setUserId("userID")};
    { // create ride photos
        maps::pgpool3::TransactionHandle txn = txnHandle();

        FeatureGateway gateway(*txn);
        gateway.insert(ridePhotos);
        txn->commit();
        for (size_t i = 0; i < ridePhotos.size(); i++) {
            houseNumberFeatures.push_back(
                HouseNumberFeature(ridePhotos[i].id(), 1 + i, 1 + i, 2 + i, 2 + i)
                .setHouseNumberId(hnssVector[houseNumberRideIdx].id())
            );
        }
    }

    TId assignmentId = insertAssigment(txnHandle());
    auto assignmentPhotos =
        Features{Feature("assignment",
                         Point2{1.0, 1.0},
                         Heading{10.0},
                         "2019-06-25 09:50:00+03",
                         mds::Key{"4510", "assignment_photo1.jpg"},
                         Dataset::Agents)
                     .setSize({6, 9})
                     .setAutomaticShouldBePublished(true)
                     .setIsPublished(true)
                     .setAssignmentId(assignmentId),
                 Feature("assignment",
                         Point2{2.0, 2.0},
                         Heading{10.0},
                         "2019-06-25 09:50:00+03",
                         mds::Key{"4510", "assignment_photo2.jpg"},
                         Dataset::Agents)
                     .setSize({6, 9})
                     .setAutomaticShouldBePublished(true)
                     .setIsPublished(true)
                     .setAssignmentId(assignmentId)};
    { // create assignment photos
        maps::pgpool3::TransactionHandle txn = txnHandle();

        FeatureGateway gateway(*txn);
        gateway.insert(assignmentPhotos);
        txn->commit();
        for (size_t i = 0; i < assignmentPhotos.size(); i++) {
            houseNumberFeatures.push_back(
                HouseNumberFeature(assignmentPhotos[i].id(), 1 + i, 1 + i, 2 + i, 2 + i)
                .setHouseNumberId(hnssVector[houseNumberAssignmentIdx].id())
            );
        }
    }

    WalkObjects walkObjects{{
        Dataset::Walks,
        "SOURCE_1",
        chrono::parseIsoDateTime("2018-07-01T18:00:00+03"),
        WalkFeedbackType::None,
        Point2{1.0, 1.0},
        "comment"
    }, {
        Dataset::Walks,
        "SOURCE_1",
        chrono::parseIsoDateTime("2018-07-02T18:00:00+03"),
        WalkFeedbackType::Other,
        Point2{2.0, 2.0},
        "comment"
    }};
    { // create walk objects
        auto txn = txnHandle();
        WalkObjectGateway gateway(*txn);
        gateway.insertx(walkObjects);
        txn->commit();
    }

    auto walkPhotos = Features{Feature{"walk",
                                       Point2{1.0, 1.0},
                                       Heading{10.0},
                                       "2019-06-25 09:50:00+03",
                                       mds::Key{"4510", "walk_photo1.jpg"},
                                       Dataset::Agents}
                                   .setSize({6, 9})
                                   .setAutomaticShouldBePublished(true)
                                   .setIsPublished(true)
                                   .setUserId("UserID")
                                   .setWalkObjectId(walkObjects[0].id()),
                               Feature{"walk",
                                       Point2{2.0, 2.0},
                                       Heading{10.0},
                                       "2019-06-25 09:50:00+03",
                                       mds::Key{"4510", "walk_photo2.jpg"},
                                       Dataset::Agents}
                                   .setSize({6, 9})
                                   .setAutomaticShouldBePublished(true)
                                   .setIsPublished(true)
                                   .setUserId("UserID")
                                   .setWalkObjectId(walkObjects[1].id())};
    { // create assignment photos
        maps::pgpool3::TransactionHandle txn = txnHandle();

        FeatureGateway gateway(*txn);
        gateway.insert(walkPhotos);
        txn->commit();
        for (size_t i = 0; i < walkPhotos.size(); i++) {
            houseNumberFeatures.push_back(
                HouseNumberFeature(walkPhotos[i].id(), 1 + i, 1 + i, 2 + i, 2 + i)
                .setHouseNumberId(hnssVector[houseNumberWalkIdx].id())
            );
        }
    }

    using namespace std::literals;
    Panoramas panoramas = {
        {"mds_key_1", "src_key_1", chrono::TimePoint{1s}, 1, 1,
         Point2{1.0, 1.0}, 1.0, 1.0, 1.0, 256, 256, 512, 512, 0},
        {"mds_key_2", "src_key_2", chrono::TimePoint{2s}, 2, 2,
         Point2{2.0, 2.0}, 2.0, 2.0, 2.0, 256, 256, 512, 512, 0},
    };

    { // create panoramas
        maps::pgpool3::TransactionHandle txn = txnHandle();

        PanoramaGateway gateway(*txn);
        gateway.insert(panoramas);
        txn->commit();
        for (size_t i = 0; i < walkPhotos.size(); i++) {
            houseNumberPanoramas.push_back(
                HouseNumberPanorama(panoramas[i].panoramaId(), 1 + i, 1 + i, 2 + i, 2 + i)
                .setHouseNumberId(hnssVector[houseNumberPanoIdx].id())
            );
        }
    }

    {
        maps::pgpool3::TransactionHandle txn = txnHandle();

        HouseNumberFeatureGateway{*txn}.insert(houseNumberFeatures);
        HouseNumberPanoramaGateway{*txn}.insert(houseNumberPanoramas);

        txn->commit();
    }

    size_t houseNumberFeaturesCount = houseNumberFeatures.size();
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        EXPECT_EQ(HouseNumberFeatureGateway{*txn}.load().size(),
                  houseNumberFeaturesCount);
        EXPECT_EQ(HouseNumberPanoramaGateway{*txn}.load().size(),
                  houseNumberPanoramas.size());
    }
}

TEST_F(Fixture, test_house_number_toloka) {

    const std::vector<HouseNumber> DATA{
        { "1", Point2{ 51.0, 51.0 } },
        { "2", Point2{ 52.0, 52.0 } },
        { "3", Point2{ 53.0, 53.0 } },
        { "4", Point2{ 54.0, 54.0 } },
        { "5", Point2{ 55.0, 55.0 } },
    };
    const std::vector<HouseNumber> DATAEXT{
        { "11", Point2{ 51.1, 51.0 } },
        { "12", Point2{ 52.1, 52.0 } },
        { "13", Point2{ 53.1, 53.0 } },
        { "14", Point2{ 54.1, 54.0 } },
    };
    const std::string workflowId         = "NIRVANA-WORKFLOW-ID";
    const std::string workflowInstanceId = "NIRVANA-WORKFLOW-INSTANCE-ID";
    const std::string blockGUID          = "NIRVANA-BLOCK-GUID";

    const std::string workflowId2         = "NIRVANA-WORKFLOW-ID-2";
    const std::string workflowInstanceId2 = "NIRVANA-WORKFLOW-INSTANCE-ID-2";
    const std::string blockGUID2          = "NIRVANA-BLOCK-GUID-2";

    HouseNumbers hnss = DATA;
    HouseNumbers hnssExt = DATAEXT;
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberGateway gtw{ *txn };
        gtw.insert(hnss);
        gtw.insert(hnssExt);
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberTolokaGateway gtw{ *txn };
        HouseNumberTolokas hnstolokas;
        for (size_t i = 0; i < hnss.size(); ++i) {
            hnstolokas.emplace_back(
                hnss[i].id(),
                workflowId,
                workflowInstanceId,
                blockGUID
            );
        }
        gtw.insert(hnstolokas);
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberTolokaGateway gtw{ *txn };
        HouseNumberTolokas hnstolokas = gtw.load(table::HouseNumberToloka::state == nirvana::nirvana_state::RUNNING);
        EXPECT_EQ(hnss.size(), hnstolokas.size());
        for (size_t i = 0; i < hnstolokas.size(); ++i) {
            hnstolokas[i].setState(nirvana::nirvana_state::FAILED);
        }
        gtw.update(hnstolokas);
        txn->commit();
    }
    {
        TIds ids;
        for (size_t i = 0; i < hnss.size(); i++) {
            ids.push_back(hnss[i].id());
        }

        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberTolokaGateway gtw{ *txn };
        HouseNumberTolokas hnstolokas = gtw.load(
            (table::HouseNumberToloka::workflowId == workflowId) &&
            (table::HouseNumberToloka::workflowInstanceId == workflowInstanceId) &&
            (table::HouseNumberToloka::blockGUID == blockGUID));
        EXPECT_EQ(hnss.size(), hnstolokas.size());
        for (size_t i = 0; i < hnstolokas.size(); ++i) {
            hnstolokas[i].restartNirvana(
                workflowId2,
                workflowInstanceId2,
                blockGUID2
            );
        }
        for (size_t i = 0; i < hnssExt.size(); ++i) {
            hnstolokas.emplace_back(
                hnssExt[i].id(),
                workflowId2,
                workflowInstanceId2,
                blockGUID2
            );
        }
        gtw.upsert(hnstolokas);
        txn->commit();
    }
    {
        maps::pgpool3::TransactionHandle txn = txnHandle();
        HouseNumberTolokaGateway gtw{ *txn };
        HouseNumberTolokas hnstolokas = gtw.load(
            (table::HouseNumberToloka::workflowId == workflowId2) &&
            (table::HouseNumberToloka::workflowInstanceId == workflowInstanceId2) &&
            (table::HouseNumberToloka::blockGUID == blockGUID2));
        EXPECT_EQ(hnss.size() + hnssExt.size(), hnstolokas.size());
        for (size_t i = 0; i < hnstolokas.size(); ++i) {
            EXPECT_EQ(hnstolokas[i].workflowId(), workflowId2);
            EXPECT_EQ(hnstolokas[i].workflowInstanceId(), workflowInstanceId2);
            EXPECT_EQ(hnstolokas[i].blockGUID(), blockGUID2);
            EXPECT_EQ(hnstolokas[i].state(), nirvana::nirvana_state::RUNNING);
        }
        txn->commit();
    }
}

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