#include "road_conditions.h"

#include <maps/wikimap/mapspro/libs/masstransit/masstransit.h>

namespace maps::wiki::masstransit {

namespace {

bool
accessedByBus(DBID accessId)
{
    constexpr DBID BUS_BIT = 1 << 1;
    return accessId & BUS_BIT;
}

} // namespace

YmapsdfRoadConditionsHandler::YmapsdfRoadConditionsHandler(Masstransit& masstransit)
    : YmapsdfObjectHandler(masstransit, masstransit.roadConditions)
{ }

std::string
YmapsdfRoadConditionsHandler::loadIdsSql() const
{
    return "SELECT cond_id AS id FROM cond "
           "WHERE cond_type IN (1, 3)"; // prohibited or permitted maneuver
}

std::string
YmapsdfRoadConditionsHandler::loadRowsSqlTemplate() const
{
    return "SELECT "
               "cond.cond_id AS id, "
               "cond.cond_type, "
               "cond.access_id, "
               "cond_from.rd_el_id from_rd_el_id, "
               "cond_from.rd_jc_id via_jc_id, "
               "ARRAY_AGG(cond_to.rd_el_id ORDER BY cond_to.seq_num) AS to_rd_el_ids "
           "FROM cond "
           "JOIN cond_rd_seq cond_from "
               "ON (cond_from.cond_seq_id = cond.cond_seq_id AND cond_from.seq_num = 0) "
           "JOIN cond_rd_seq cond_to "
               "ON (cond_to.cond_seq_id = cond.cond_seq_id AND cond_to.seq_num > 0) "
           "WHERE cond_id IN %1%"
           "GROUP BY 1, 2, 3, 4, 5";
}

void
YmapsdfRoadConditionsHandler::addObject(const pqxx::row& tuple)
{
    const auto condId = getAttr<DBID>(tuple, ymapsdf::ID);
    const auto condTypeId = getAttr<DBID>(tuple, ymapsdf::COND_TYPE);
    const auto condType = toConditionType(condTypeId);
    const auto accessId = getAttr<DBID>(tuple, ymapsdf::ACCESS_ID);
    const auto fromRdElId = getAttr<DBID>(tuple, ymapsdf::FROM_RD_EL_ID);
    const auto viaRdJcId = getAttr<DBID>(tuple, ymapsdf::VIA_RD_JC_ID);
    const auto toRdElIds = getAttr<Ids>(tuple, ymapsdf::TO_RD_EL_IDS);

    if (!accessedByBus(accessId)) {
        return;
    }

    auto& conditions = roadConditions(masstransit_);
    conditions.emplace_back(condId, condType, fromRdElId, viaRdJcId, toRdElIds);
}

Conditions&
roadConditions(Masstransit& masstransit)
{
    const size_t ROAD_CONDITIONS_GLOBAL_ID = 0;
    if (!masstransit.roadConditions.count(ROAD_CONDITIONS_GLOBAL_ID)) {
        masstransit.roadConditions.insert(
            ROAD_CONDITIONS_GLOBAL_ID,
            std::make_shared<RoadConditions>());
    }
    return masstransit.roadConditions[ROAD_CONDITIONS_GLOBAL_ID].conditions;
}

} // namespace maps::wiki::masstransit
