#include "yt_row_to_feedback.h"
#include "column_names.h"
#include "common.h"
#include "feedback_description_links.h"
#include "serialization.h"

#include <maps/libs/geolib/include/conversion.h>
#include <yandex/maps/wiki/social/feedback/attributes.h>
#include <yandex/maps/wiki/social/feedback/attribute_names.h>
#include <yandex/maps/wiki/social/feedback/description_keys.h>
#include <yandex/maps/wiki/social/feedback/description.h>
#include <yandex/maps/wiki/social/feedback/enums.h>
#include <maps/libs/common/include/exception.h>

namespace maps::wiki::route_lost_feedback {

namespace sf = social::feedback;
namespace bg = boost::gregorian;

namespace {

sf::DescriptionI18n
constructFeedbackDescription(
    const NYT::TNode& row,
    bg::date_period datesPeriod)
{
    ASSERT(datesPeriod.length() != bg::date_duration(0));

    uint64_t countDays = datesPeriod.length().days();
    uint64_t countLosts = row[column_names::LOSTS_NUMBER].AsUint64();
    uint64_t countTracks = row[column_names::TRACKS_NUMBER].AsUint64();

    sf::ParamToDescription descrParams;

    descrParams[sf::tanker::ROUTE_LOSTS_PER_DAY] = sf::Description(
        std::to_string(1. * countLosts / countDays)
    );

    descrParams[sf::tanker::TRACKS_PER_DAY] = sf::Description(
        std::to_string(1. * countTracks / countDays)
    );

    FeedbackDescriptionLinksGenerator linksGen(row);

    descrParams[sf::tanker::ROUTE_LOST_LOCAL_LINK] = sf::Description(
        linksGen.localLink()
    );

    descrParams[sf::tanker::ROUTE_LOST_LOCAL_USER_LINK] = sf::Description(
        linksGen.localUserLink()
    );

    descrParams[sf::tanker::ROUTE_LOST_LOCAL_NAVI_LINK] = sf::Description(
        linksGen.localNaviLink()
    );
    descrParams[sf::tanker::ROUTE_LOST_GLOBAL_NAVI_LINK] = sf::Description(
        linksGen.globalNaviLink()
    );

    return sf::DescriptionI18n (
        sf::tanker::fb_desc::ROUTE_LOST_DETAILED_KEY,
        std::move(descrParams)
    );
}

json::Value
constructUserAttrs(
    const NYT::TNode& row,
    bg::date_period datesPeriod)
{
    uint64_t countLosts = row[column_names::LOSTS_NUMBER].AsUint64();
    uint64_t countTracks = row[column_names::TRACKS_NUMBER].AsUint64();

    return json::Value (
        json::repr::ObjectRepr{
           {"countLosts", json::Value(countLosts)},
           {"countTracks", json::Value(countTracks)},
           {"routeId", json::Value(row[column_names::ROUTE_ID].AsString())},
           {"routeStartPos", toJson(asPoint(row[column_names::ROUTE_START]))},
           {"routeEndPos", toJson(asPoint(row[column_names::ROUTE_END]))},
           {
               "dayBegin",
               json::Value(bg::to_iso_extended_string(datesPeriod.begin()))
           },
           {
               "dayEnd",
               json::Value(bg::to_iso_extended_string(datesPeriod.end()))
           },
           {
               sf::attrs::AFTER_LOST_ROUTE_SEGMENT,
               toJson(
                   asPersistentSegment(
                       row[column_names::AFTER_LOST_ROUTE_SEGMENT]
                   )
               )
           },
           {
               sf::attrs::AFTER_LOST_TRACK_SEGMENT,
               toJson(
                   asPersistentSegment(
                       row[column_names::AFTER_LOST_TRACK_SEGMENT]
                   )
               ),
           },
           {
               sf::attrs::BEFORE_LOST_SEGMENT,
               toJson(
                   asPersistentSegment(
                       row[column_names::BEFORE_LOST_SEGMENT]
                   )
               )
           }
        }
    );
}

} // unnamed namespace

social::feedback::TaskNew
ytRowToFeedback(
    const NYT::TNode& row,
    bg::date_period datesPeriod)
{
    auto position = geolib3::convertGeodeticToMercator(
        asPoint(row[column_names::LOST_POINT])
    );

    sf::TaskNew newTask(
        position,
        sf::Type::RouteLost,
        "route-lost",
        constructFeedbackDescription(row, datesPeriod)
    );
    newTask.hidden = true;
    newTask.attrs.add(sf::AttrType::UserData, constructUserAttrs(row, datesPeriod));

    return newTask;
}

} // namespace maps::wiki::route_lost_feedback
