#include <maps/wikimap/mapspro/services/mrc/libs/db/include/feature_gateway.h>

namespace maps::mrc::db {

Features FeatureGateway::loadSequence(TId baseFeatureId, size_t beforeLimit, size_t afterLimit) {
    auto base = tryLoadOne(Tb::id == baseFeatureId && publishingFeatures());
    if (!base) {
        return {};
    }

    if (base->sourceId() == feature::NO_SOURCE_ID) {
        return {*base};
    }

    using sql_chemistry::orderBy;
    const auto isAdjacent = Tb::sourceId == base->sourceId() && publishingFeatures();

    // requests are optimized to use (source_id, date) index
    Features res = load(isAdjacent && Tb::date < base->timestamp(),
        orderBy(Tb::date).desc().limit(beforeLimit));
    std::reverse(res.begin(), res.end());

    // second set is disjoint from the first and includes base feature
    loadInto(std::back_inserter(res), isAdjacent && Tb::date >= base->timestamp(),
        orderBy(Tb::date).asc().limit(afterLimit + 1));

    // force uniform unique order in case of equal timestamps
    std::sort(res.begin(), res.end(), [](auto& f1, auto& f2) {
        return std::make_tuple(f1.timestamp(), f1.id()) < std::make_tuple(f2.timestamp(), f2.id());
    });
    return res;
}

std::vector<std::string> FeatureGateway::loadAllSources()
{
    auto result = std::vector<std::string>{};
    auto query = std::ostringstream{} << "select distinct "
                                      << Tb::sourceId.selectStatement() << " "
                                      << fromTable();
    const auto rows = exec(query.str());
    for (const auto& row : rows) {
        result.push_back(Tb::sourceId.unescapeField(row[0]));
    }
    return result;
}

} // namespace maps::mrc::db
