#pragma once

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

#include <maps/wikimap/mapspro/services/mrc/eye/lib/detection/include/store.h>
#include <maps/wikimap/mapspro/services/mrc/eye/lib/object_manager/impl/passage.h>

#include <vector>

namespace maps::mrc::eye {

// Проверяет, что в двух множествах детекций нет двух
// разных детекций на одной и той же фотографии.
// При этом, если в каждом из двух множеств есть одна и
// та же детекция, то этот факт игнорируется.
// Пример:
// Имеем 4 детекции на трех изображениях:
//     {frameId = 0, detectionId = 0},
//     {frameId = 0, detectionId = 1},
//     {frameId = 1, detectionId = 2},
//     {frameId = 2, detectionId = 3}
// Тогда функция будет возвращать следующие значения
// при разных значениях в аргументах:
//   Вход:
//     1) detectionIds1 = {0, 2},
//     2) detectionIds2 = {1, 3}
//   Результат:
//     true - т.е. есть две детекции на одном изображении,
//     так как detectionId = 0 и detectionId = 1 располагаются
//     на frameId = 0
//
//  Вход:
//    1) detectionIds1 = {0, 2},
//    2) detectionIds2 = {0, 3}
//  Результат:
//    false - т.е. нет двух детекций на одном изображении.
//    Хоть и оба множества detectionIds1 и detectionIds2
//    содержат детекцию detectionId = 0, этот факт игнорируется
//    При вычислении результата
//
//  Вход:
//    1) detectionIds1 = {1, 2}
//    2) detectionIds2 = {3}
//  Результат:
//    false - т.е. нет двух детекций на одном изображении.
//    Такой результат получится из-за того что все три
//    детекции сделаны на трех разных изображениях
bool hasDifferentDetectionsOnSameFrame(
    const DetectionStore& store,
    const db::TIdSet& detectionIds1,
    const db::TIdSet& detectionIds2);


// Производит слияние объектов из разных проездов основываясь
// на упорядоченном множестве матчей между объектами.
//
// * objectMatches - множество матчей между объектами.
//                   Порядок матчей в массиве важен, так как
//                   он учитывается в алгоритме слияния.
//                   Матчи должны быть упорядочены в порядке предпочтения
//                   слияния объектов, соответствующих матчу (например -
//                   - упорядочены по убыванию confidence)
//                   !! ВАЖНО !! порядок матчей никак не проверяется.
//                   Ответственность в правильном упорядочивании матчей
//                   лежит на разработчике, который вызывает эту функцию.
//
//  areAllowedToMerge -- функция, определяющая, могут ли данные два множества
//  детекций быть объединены в один кластер
//
// Алгоритм слияния:
//   1) Последовательно проходим весь массив матчей, обрабатывая каждый матч
//      по отдельности. При этом считаем, что все матчи упорядочены по confidence
//   2) Находим индексы объектов, в которое уже (возможно) слились объекты из
//      текущего матча, в результате имеем objectIndx1 и objectIndx2, которые
//      могут быть и не определены (если объекты из матча еще никуда не вливались)
//   3.1) Если objectIndx1 и objectIndx2 не определены, т.е. оба объекта еще никуда
//      не вливались, то нужно слить их в один новый объект, если это разрешено areAllowedToMerge.
//   3.2) Если objectIndx1 и objectIndx2 оба определены, т.е. оба объекта уже
//        ранее принимали участие в каком-то слиянии объектов, то нужно слить два
//        объекта в которые слились объекты из матча, предварительно проверив, если это
//        разрешено areAllowedToMerge
//   3.3) Если неопределен только один индекс объекта (для определенности будем
//        считать, что objectIndx1 определен, а objectIndx2 - нет), то нужно добавить
//        объект из проезда в новый объект, который ранее получился после некоторого
//        слияния, если это разрешает areAllowedToMerge
//   4) Если какой-то объект не поучаствовал в слиянии на шагах 4.1) - 4.3), то его
//      надо добавить в множество результирующих объектов без каких-либо изменений
std::vector<db::TIdSet> greedyObjectsMerging(
    const std::vector<MatchedObjects>& objectsMatches,
    const std::vector<ObjectsInPassage>& objectsByPassages,
    std::function<bool(const db::TIdSet&, const db::TIdSet&)> areAllowedToMerge);

} // namespace maps::mrc::eye
