#include "../fixtures.h"
#include "../../lib/fbapi/consts.h"
#include "../../lib/fbapi/traits.h"
#include "../../lib/fbapi/report_addr.h"
#include "../../lib/fbapi/report_addr_heuristics.h"
#include "../../lib/fbapi/report_addr_strategy.h"

#include <yandex/maps/wiki/social/feedback/attribute_names.h>
#include <yandex/maps/wiki/social/feedback/description.h>
#include <yandex/maps/wiki/social/feedback/gateway_rw.h>
#include <maps/libs/geolib/include/point.h>

#include <library/cpp/testing/unittest/registar.h>

namespace maps::wiki::schedule_feedback::tests{

namespace chr = std::chrono;
namespace sf = social::feedback;
namespace sfa = social::feedback::attrs;

namespace {

const geolib3::Point2 SOME_COORDS(0., 0.);
const ObjId SOME_OBJ = 123;
const std::string SOME_STREET = "ул льва Толстого";
const std::string SOME_HOUSE = "16";

const social::TUid USER_ID = 1001;

auto DESCR()
{
    return sf::Description("descr");
}

sf::TaskNew reportAddressNewTask(
    ObjId addrObjId,
    const geolib3::Point2& coords,
    const std::string& street,
    const std::string& house)
{
    sf::TaskNew newTask(coords, sf::Type::Address, FBAPI, DESCR());
    newTask.objectId = addrObjId;
    newTask.attrs.addCustom(sfa::SUBSOURCE, "qid__wrong_address__aid__report_address");
    newTask.attrs.addCustom(sfa::STREET, street);
    newTask.attrs.addCustom(sfa::HOUSE, house);
    return newTask;
}

sf::TaskNew typicalReportAddressNewTask()
{
    return reportAddressNewTask(SOME_OBJ, SOME_COORDS, SOME_STREET, SOME_HOUSE);
}

sf::TaskNew invalidReportAddressNewTask()
{
    return sf::TaskNew(SOME_COORDS, sf::Type::Entrance, FBAPI, DESCR());
}

} // anonymous

Y_UNIT_TEST_SUITE(fbapi_report_addr_tests) {

Y_UNIT_TEST_F(traits, DBFixture)
{
    auto coreTxn = pool().masterReadOnlyTransaction();
    auto socialTxn = pool().masterWriteableTransaction();
    sf::GatewayRW gatewayRw(socialTxn.get());

    //////////////
    /// Traits ///
    //////////////
    {
        sf::TaskNew newTask(SOME_COORDS, sf::Type::Entrance,
                            FBAPI, DESCR());
        auto task = gatewayRw.addTask(USER_ID, newTask);
        UNIT_ASSERT(!isAddressReportAddressTask(task));
    }
    {
        sf::TaskNew newTask(SOME_COORDS, sf::Type::Address,
                            FBAPI, DESCR());
        newTask.attrs.addCustom(
            sfa::SUBSOURCE,
            "qid__wrong_address__aid__report_address"
        );
        auto task = gatewayRw.addTask(USER_ID, newTask);
        UNIT_ASSERT(isAddressReportAddressTask(task));
    }

    //////////////////
    /// Convertion ///
    //////////////////
    {
        auto task = gatewayRw.addTask(USER_ID, typicalReportAddressNewTask());
        auto fb = socialTaskToReportAddressFb(task);

        UNIT_ASSERT_EQUAL(fb.createdAt, task.createdAt());
        UNIT_ASSERT_VALUES_EQUAL(fb.feedbackId, task.id());
        UNIT_ASSERT_VALUES_EQUAL(fb.addressObjectId, SOME_OBJ);
        UNIT_ASSERT_STRINGS_EQUAL(fb.address.street, SOME_STREET);
        UNIT_ASSERT_STRINGS_EQUAL(fb.address.house, SOME_HOUSE);
        UNIT_ASSERT_DOUBLES_EQUAL(fb.positionMerc.x(), 0., 1.e-6);
        UNIT_ASSERT_DOUBLES_EQUAL(fb.positionMerc.y(), 0., 1.e-6);
    }
    {
        auto task = gatewayRw.addTask(USER_ID, invalidReportAddressNewTask());
        UNIT_ASSERT_NO_EXCEPTION(socialTaskToReportAddressFbNoExcept(task));
    }

    /////////////////
    /// Rejection ///
    /////////////////
    {
        // Invalid social task
        auto task = gatewayRw.addTask(USER_ID, invalidReportAddressNewTask());
        auto action = reportAddressTaskHeuristicsAction(
            task, coreTxn.get());
        UNIT_ASSERT(std::holds_alternative<ReportAddrNoneAction>(action));
    }
    {
        // Address can't be normalized
        auto task = gatewayRw.addTask(USER_ID,
            reportAddressNewTask(SOME_OBJ, SOME_COORDS, "ленина", "фыва"));

        auto action = reportAddressTaskHeuristicsAction(
            task, coreTxn.get());
        UNIT_ASSERT(std::holds_alternative<ReportAddrRejectAction>(action));
        UNIT_ASSERT(std::get<ReportAddrRejectAction>(action).reason ==
                    ReportAddrRejectAction::Reason::NonNormalizable);
    }
    {
        // Object id is not 'Address' object id
        auto task = gatewayRw.addTask(USER_ID, typicalReportAddressNewTask());

        auto action = reportAddressTaskHeuristicsAction(
            task, coreTxn.get());
        UNIT_ASSERT(std::holds_alternative<ReportAddrRejectAction>(action));
        UNIT_ASSERT(std::get<ReportAddrRejectAction>(action).reason ==
                    ReportAddrRejectAction::Reason::ObjectIsNotAddress);
    }
}

} // Y_UNIT_TEST_SUITE(fbapi_report_addr_tests)

} // namespace maps::wiki::schedule_feedback::tests
