#include <maps/wikimap/mapspro/services/mrc/eye/lib/common/include/id.h>

#include <algorithm>
#include <iterator>

namespace maps::mrc::eye {

void insert(db::TIdSet& toInsert, const db::TIdSet& ids)
{
    toInsert.insert(ids.begin(), ids.end());
}

db::TIdSet join(db::TIdSet lhs, const db::TIdSet& rhs)
{
    insert(lhs, rhs);
    return lhs;
}

db::TIds join(db::TIds left, db::TIds right)
{
    std::sort(left.begin(), left.end());
    std::sort(right.begin(), right.end());

    db::TIds result;

    std::set_union(
        left.begin(), left.end(),
        right.begin(), right.end(),
        std::back_inserter(result)
    );

    return result;
}

db::TIdSet diff(db::TIdSet lhs, const db::TIdSet& rhs)
{
    for (auto id: rhs) {
        lhs.erase(id);
    }

    return lhs;
}

db::TIds diff(db::TIds left, db::TIds right)
{
    std::sort(left.begin(), left.end());
    std::sort(right.begin(), right.end());

    db::TIds result;

    std::set_difference(
        left.begin(), left.end(),
        right.begin(), right.end(),
        std::back_inserter(result)
    );

    return result;
}

bool intersected(const db::TIdSet& lhs, const db::TIdSet& rhs)
{
    return std::any_of(
        lhs.begin(), lhs.end(),
        [&](db::TId id) {
            return rhs.count(id);
        }
    );
}

db::IdTo<db::TId> reverse(const db::IdTo<db::TId>& idMap)
{
    db::IdTo<db::TId> result;

    for (auto [key, value]: idMap) {
        result.emplace(value, key);
    }

    return result;
}

bool operator<(const FrameDetectionId& lhs, const FrameDetectionId& rhs) {
    return std::tuple(lhs.frameId, lhs.detectionId)
         < std::tuple(rhs.frameId, rhs.detectionId);
}

bool operator==(const FrameDetectionId& lhs, const FrameDetectionId& rhs) {
    return std::tuple(lhs.frameId, lhs.detectionId)
        == std::tuple(rhs.frameId, rhs.detectionId);
}

} // namespace maps::mrc::eye
