#include "fixture.h"

#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/tasks_group_gateway.h>
#include <maps/libs/geolib/include/test_tools/comparison.h>
#include <maps/libs/geolib/include/conversion.h>
#include <library/cpp/testing/gtest/gtest.h>

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

namespace {

using geolib3::Polygon2;
using geolib3::MultiPolygon2;
using geolib3::PointsVector;

bool isEqual(const TasksGroup& lhs, const TasksGroup& rhs) {
    return lhs.id() == rhs.id() &&
        lhs.status() == rhs.status() &&
        lhs.name() == rhs.name() &&
        geolib3::test_tools::approximateEqual(
            lhs.mercatorGeom(), rhs.mercatorGeom(), 0) &&
        lhs.useRouting() == rhs.useRouting() &&
        lhs.fcs() == rhs.fcs() &&
        lhs.useToll() == rhs.useToll() &&
        lhs.recommendedTaskLengthMeters() == rhs.recommendedTaskLengthMeters() &&
        lhs.minEdgeCoverageRatio() == rhs.minEdgeCoverageRatio() &&
        lhs.excludeDeadends() == rhs.excludeDeadends() &&
        lhs.ignorePrivateArea() == rhs.ignorePrivateArea() &&
        lhs.actualizedBefore() == rhs.actualizedBefore() &&
        lhs.totalLengthMeters() == rhs.totalLengthMeters() &&
        lhs.uniqueLengthMeters() == rhs.uniqueLengthMeters() &&
        lhs.graphCoverageRatio() == rhs.graphCoverageRatio() &&
        lhs.cameraDeviations() == rhs.cameraDeviations();
}

} // namespace

using Fixture = maps::mrc::db::tests::Fixture;

TEST_F(Fixture, test_tasks_group_gateway) {
    TasksGroup a{
        TasksGroupStatus::Draft,
        "Moscow 2018.02",
        geolib3::convertGeodeticToMercator(
            MultiPolygon2{
                {Polygon2{PointsVector{{37.6, 55.6},
                    {37.7, 55.6},
                    {37.7, 55.7},
                    {37.6, 55.6}
                }}
                }}
        ),
        UseRouting::No,
        {1, 2, 3, 4, 5, 6, 7},
        UseToll::No,
        10000
    };

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        gtw.insert(a);
        txn->commit();
    }

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        auto ids = gtw.loadIds();
        EXPECT_EQ(ids.size(), 1u);
        EXPECT_TRUE(isEqual(a, gtw.loadById(a.id())));
    }

    TasksGroup aChanged = a;
    aChanged.setStatus(TasksGroupStatus::Open);
    aChanged.setTotalLengthMeters(1000);
    aChanged.setUniqueLengthMeters(2000);
    aChanged.setGraphCoverageRatio(0.9);
    aChanged.setRecommendedTaskLengthMeters(2000);
    aChanged.setCameraDeviations(
        {CameraDeviation::Front, CameraDeviation::Right});
    aChanged.setCreatedBy("123");
    aChanged.setMinEdgeCoverageRatio(0.1);
    aChanged.setExcludeDeadends(true);
    aChanged.setIgnorePrivateArea(true);

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        gtw.update(aChanged);
        txn->commit();
    }

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        auto aLoaded = gtw.loadById(a.id());
        EXPECT_FALSE(isEqual(a, aLoaded));
        EXPECT_TRUE(isEqual(aChanged, aLoaded));

        EXPECT_TRUE(aLoaded.minEdgeCoverageRatio().has_value());
        EXPECT_FLOAT_EQ(aLoaded.minEdgeCoverageRatio().value(), 0.1);
        EXPECT_TRUE(aLoaded.excludeDeadends());
    }

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        gtw.removeById(a.id());
        txn->commit();
    }

    {
        auto txn = txnHandle();
        TasksGroupGateway gtw(*txn);
        auto ids = gtw.loadIds();
        EXPECT_EQ(ids.size(), 0u);
    }
}

TEST_F(Fixture, test_tasks_group_email)
{
    auto makeTasksGroup = [&](std::string name) {
        auto result = TasksGroup{
            TasksGroupStatus::Draft,
            std::move(name),
            convertGeodeticToMercator(MultiPolygon2{{Polygon2{PointsVector{
                {37.6, 55.6}, {37.7, 55.6}, {37.7, 55.7}, {37.6, 55.6}}}}}),
            UseRouting::No,
            {1, 2, 3, 4, 5, 6, 7},
            UseToll::No,
            10000};
        auto txn = txnHandle();
        TasksGroupGateway{*txn}.insert(result);
        txn->commit();
        return result;
    };

    auto tasksGroupId = makeTasksGroup("N.Novgorod 2021.01").id();
    auto tasksGroupEmails = TasksGroupEmails{};
    auto EMAIL_1 = "a1@yandex.ru";
    auto EMAIL_2 = "a2@yandex.ru";
    auto EMAIL_3 = "a3@yandex.ru";
    tasksGroupEmails.emplace_back(tasksGroupId, EMAIL_1);
    tasksGroupEmails.emplace_back(tasksGroupId, EMAIL_2);
    tasksGroupEmails.emplace_back(makeTasksGroup("St.Petersburg 2021.02").id(),
                                  EMAIL_3);

    {
        auto txn = txnHandle();
        TasksGroupEmailGateway{*txn}.insert(tasksGroupEmails);
        txn->commit();
    }
    EXPECT_EQ(TasksGroupEmailGateway(*txnHandle())
                  .count(table::TasksGroupEmail::tasksGroupId == tasksGroupId),
              2u);

    {
        auto txn = txnHandle();
        TasksGroupEmailGateway{*txn}.remove(
            table::TasksGroupEmail::tasksGroupId == tasksGroupId &&
            table::TasksGroupEmail::email == EMAIL_1);
        txn->commit();
    }
    tasksGroupEmails = TasksGroupEmailGateway{*txnHandle()}.load(
        table::TasksGroupEmail::tasksGroupId == tasksGroupId);
    EXPECT_EQ(tasksGroupEmails.size(), 1u);
    EXPECT_EQ(tasksGroupEmails.front().email(), EMAIL_2);

    {
        auto txn = txnHandle();
        TasksGroupGateway{*txn}.removeById(tasksGroupId);
        txn->commit();
    }

    EXPECT_EQ(TasksGroupEmailGateway(*txnHandle())
                  .count(table::TasksGroupEmail::tasksGroupId == tasksGroupId),
              0u);
}

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