#include "features_index.h"

#include <maps/libs/geolib/include/spatial_relation.h>

namespace maps::mrc::graph_coverage_export {

namespace {

db::TIds searchFeatureIdsByBbox(
    const fb::FeaturesReader& reader, const geolib3::BoundingBox& bbox)
{
    auto range = reader.rtree().allIdsInWindow(
        bbox, [&](const geolib3::BoundingBox& box, fb_rtree::Id id) {
            auto feature = reader.featureById(id);
            ASSERT(feature.has_value());
            return geolib3::spatialRelation(
                box, feature->geodeticPos(), geolib3::Intersects);
        });
    return db::TIds(range.begin(), range.end());
}

} // namespace

db::Feature
FeaturesIndex::featureById(db::TId featureId) const
{
    auto featureOpt = defaultFeaturesReader_.featureById(featureId);
    if (!featureOpt.has_value()) {
        featureOpt = secretFeaturesReader_.featureById(featureId);
    }
    ASSERT(featureOpt.has_value());
    return featureOpt.value();
}

db::TIds FeaturesIndex::featureIds() const
{
    db::TIds result;
    const size_t totalFeaturesNumber = defaultFeaturesReader_.featuresNumber() +
        secretFeaturesReader_.featuresNumber();
    result.reserve(totalFeaturesNumber);
    for (size_t i = 0; i < defaultFeaturesReader_.featuresNumber(); ++i) {
        result.push_back(defaultFeaturesReader_.feature(i).id());
    }
    for (size_t i = 0; i < secretFeaturesReader_.featuresNumber(); ++i) {
        result.push_back(secretFeaturesReader_.feature(i).id());
    }
    return result;
}

db::TIds FeaturesIndex::featureIdsInBbox(const geolib3::BoundingBox& bbox) const
{
    db::TIds featuresIds = searchFeatureIdsByBbox(defaultFeaturesReader_, bbox);
    db::TIds secretFeaturesIds = searchFeatureIdsByBbox(secretFeaturesReader_, bbox);

    featuresIds.reserve(featuresIds.size() + secretFeaturesIds.size());
    featuresIds.insert(
        featuresIds.end(),
        secretFeaturesIds.begin(),
        secretFeaturesIds.end());
    return featuresIds;
}

} // namespace maps::mrc::graph_coverage_export
