#include <maps/wikimap/mapspro/services/tasks_feedback/src/import_feedback_worker/lib/worker.h>

#include <maps/libs/log8/include/log8.h>
#include <maps/libs/geolib/include/conversion.h>
#include <yandex/maps/wiki/unittest/localdb.h>
#include <yandex/maps/wiki/social/feedback/description.h>
#include <yandex/maps/wiki/social/feedback/gateway_rw.h>
#include <boost/test/unit_test.hpp>

namespace maps::wiki::import_feedback::tests {

namespace sf = social::feedback;

namespace {

struct SetLogLevelFixture
{
    SetLogLevelFixture() {
        maps::log8::setLevel(maps::log8::Level::FATAL);
    }
};

class DBFixture : public unittest::MapsproDbFixture, public SetLogLevelFixture
{
public:
    DBFixture()
        : unittest::MapsproDbFixture()
    {}
};

TaskParams taskParamsFromData(std::string data)
{
    return TaskParams(
        1,
        "source-string",
        sf::Type::Address,
        sf::Workflow::Feedback,
        false,
        std::move(data));
}

void doTestImport(std::string data, pgpool3::Pool& pool)
{
    auto taskParams = taskParamsFromData(std::move(data));

    auto txn = pool.masterWriteableTransaction();
    importRoutine(taskParams, txn.get());
    txn->commit();
}

} // anonymous namespace

BOOST_FIXTURE_TEST_CASE(test_correct_load, DBFixture)
{
    std::string data = \
        "lon\tlat\tdescription\tobject_id\n"\
        "33.33\t55.55\tsome description\t12341345";

    doTestImport(data, pool());

    auto txn = pool().masterWriteableTransaction();
    auto allTasks = sf::GatewayRO(txn.get()).tasksByFilter(
        sf::TaskFilter());
    BOOST_CHECK_EQUAL(allTasks.size(), 1);
    const auto& task = allTasks[0];

    auto geoPosition = geolib3::convertMercatorToGeodetic(task.position());
    BOOST_CHECK(geoPosition == geolib3::Point2(
        33.33, 55.55
    ));
    BOOST_CHECK_EQUAL(task.type(), sf::Type::Address);
    BOOST_CHECK_EQUAL(task.workflow(), sf::Workflow::Task);
    BOOST_CHECK_EQUAL(task.source(), "experiment-source-string");
    BOOST_CHECK(task.description() == sf::Description("some description"));
    BOOST_CHECK(task.objectId());
    BOOST_CHECK_EQUAL(*task.objectId(), 12341345);
    BOOST_CHECK_EQUAL(task.hidden(), false);
}

BOOST_FIXTURE_TEST_CASE(test_multiple_correct_load, DBFixture)
{
    std::string data = \
        "lon\tlat\tdescription\tobject_id\n"\
        "33.33\t55.55\tsome description\t12341345\n"\
        "33.33\t55.55\tкакой-то текст\t345345\n"\
        "30\t50\tsome description ok\t234234";

    doTestImport(data, pool());

    auto txn = pool().masterWriteableTransaction();
    auto allTasks = sf::GatewayRO(txn.get()).tasksByFilter(
        sf::TaskFilter());
    BOOST_CHECK_EQUAL(allTasks.size(), 3);
}

BOOST_FIXTURE_TEST_CASE(test_absent_obligatory_field, DBFixture)
{
    std::string data = \
        "lon\tdescription\tobject_id\n"\
        "33.33\tsome description\t12341345";

    BOOST_CHECK_THROW(
        doTestImport(data, pool()),
        RuntimeError
    );
}

BOOST_FIXTURE_TEST_CASE(test_absent_object_id, DBFixture)
{
    std::string dataWithObjectIdInHeader = \
        "lat\tlon\tdescription\tobject_id\n"\
        "55.55\t33.33\tsome description\t\"\"";
    doTestImport(dataWithObjectIdInHeader, pool());

    std::string dataWithoutObjectIdInHeader = \
        "lat\tlon\tdescription\n"\
        "55.55\t33.33\tsome description";
    doTestImport(dataWithoutObjectIdInHeader, pool());


    auto txn = pool().masterWriteableTransaction();
    auto allTasks = sf::GatewayRO(txn.get()).tasksByFilter(
        sf::TaskFilter());
    BOOST_CHECK_EQUAL(allTasks.size(), 2);
    for (const auto& task: allTasks) {
        BOOST_CHECK(!task.objectId());
    }
}

BOOST_FIXTURE_TEST_CASE(test_malformed_row, DBFixture)
{
    std::string data = \
        "lon\tlat\tdescription\tobject_id\n"\
        "33.33\t55.55\tsome description\t12341345\n"\
        "33.33\t55.55\tsome description\t345345\n"\
        "30\t50\tsome description\n"\
        "33.33\t55.55\tsome description\t12341345";

    BOOST_CHECK_THROW(
        doTestImport(data, pool()),
        RuntimeError
    );
}

BOOST_FIXTURE_TEST_CASE(test_cleanup, DBFixture)
{
    auto txn = pool().masterWriteableTransaction();

    BOOST_CHECK_NO_THROW(
        cleanupOldFiles(txn.get())
    );
}


} // namespace maps::wiki::import_feedback::tests
