#ifndef MAPS_MRC_COMMON_GEOEMTRY_INL
#error "Direct inclusion of geoemtry-inl.h is not allowed"
    ", please include geoemtry.h instead"
#endif

#include <map>
#include <optional>

namespace maps::mrc::common::geometry {

namespace internal {

template<typename Value,
         typename Cmp,
         typename PolylinePosToValueMap = std::map<PolylinePosition, std::optional<Value>>>
PolylinePosToValueMap
makePolylinePosToValueMap(const std::vector<SubPolylineWithValue<Value>>& items, Cmp cmp)
{
    PolylinePosToValueMap result;
    for (const auto& item : items) {
        if (!item.subPolyline.empty()) {
            result.emplace(item.subPolyline.begin(), std::nullopt);
            result.emplace(item.subPolyline.end(), std::nullopt);
        }
    }

    for (const auto& item : items) {
        if (!item.subPolyline.empty()) {
            auto beginPosIt = result.find(item.subPolyline.begin());
            auto endPosIt = result.find(item.subPolyline.end());
            for (auto it = beginPosIt; it != endPosIt; ++it) {
                if (it->second.has_value()) {
                    it->second = std::max(it->second.value(), item.value, cmp);
                } else {
                    it->second = item.value;
                }
            }
        }
    }
    return result;
}

} // namespace internal

template<typename Value, typename Cmp>
std::vector<SubPolylineWithValue<Value>>
merge(const std::vector<SubPolylineWithValue<Value>>& items, Cmp cmp)
{
    std::vector<SubPolylineWithValue<Value>> result;
    auto posToValueMap = internal::makePolylinePosToValueMap(items, cmp);
    for (auto it = posToValueMap.begin(); it != posToValueMap.end();) {
        auto value = it->second;
        auto nextIt =
            std::find_if(it, posToValueMap.end(), [value](auto& item) {
                return item.second != value;
            });
        if (value.has_value()) {
            ASSERT(nextIt != posToValueMap.end());
            result.emplace_back(SubPolyline(it->first, nextIt->first), value.value());
        }
        it = nextIt;
    }
    return result;
}

} // namespace maps::mrc::common::geometry
