#include <maps/wikimap/mapspro/services/mrc/long_tasks/toloka_manager_cron_jobs/lib/include/detection_missing_on_frame.h>

namespace maps {
namespace mrc {
namespace toloka {

DetectionMissingOnFrameIsVisible evalIsVisible(
    const DetectionMissingOnFrame::AssignmentResults& results,
    size_t taskIdx)
{
    std::vector<DetectionMissingOnFrameIsVisible> items;
    for (const auto& res : results) {
        items.push_back(res.outputs[taskIdx].isVisible());
    }

    std::sort(items.begin(), items.end());
    const auto range = longestEqualRange(items.begin(), items.end());
    if ((size_t)std::distance(range.first, range.second) <= items.size() / 2) {
        return DetectionMissingOnFrameIsVisible::Unknown;
    }

    if (DetectionMissingOnFrameIsVisible::NotLoaded == *range.first) {
        return DetectionMissingOnFrameIsVisible::Unknown;
    }

    return *range.first;
}

DetectionMissingOnFrameMissingReason evalMissingReason(
    const DetectionMissingOnFrame::AssignmentResults& results,
    size_t taskIdx)
{
    std::vector<DetectionMissingOnFrameMissingReason> items;
    for (const auto& res : results) {
        if (res.outputs[taskIdx].missingReason().has_value()) {
            items.push_back(res.outputs[taskIdx].missingReason().value());
        }
    }

    std::sort(items.begin(), items.end());
    const auto range = longestEqualRange(items.begin(), items.end());
    if ((size_t)std::distance(range.first, range.second) <= items.size() / 2) {
        return DetectionMissingOnFrameMissingReason::Unknown;
    }

    return *range.first;
}

DetectionMissingOnFrame::TaskOutput DetectionMissingOnFrame::mergeSingleTaskResults(
    const DetectionMissingOnFrame::AssignmentResults& results,
    size_t taskIdx)
{
    DetectionMissingOnFrameIsVisible isVisible = evalIsVisible(results, taskIdx);

    std::optional<DetectionMissingOnFrameMissingReason> missingReason;
    if (DetectionMissingOnFrameIsVisible::No == isVisible) {
        missingReason = evalMissingReason(results, taskIdx);
    }

    return DetectionMissingOnFrame::TaskOutput{isVisible, missingReason};
}

DetectionMissingOnFrame::TaskSuiteResult DetectionMissingOnFrame::mergeTaskSuiteResults(
    const DetectionMissingOnFrame::AssignmentResults& assignmentResults)
{
    DetectionMissingOnFrame::TaskSuiteResult tsResult;

    REQUIRE(!assignmentResults.empty(), "Empty task suite results");
    size_t tasksCount = assignmentResults[0].inputs.size();

    for (size_t i = 0; i < tasksCount; ++i) {
        DetectionMissingOnFrame::TaskInput input = assignmentResults[0].inputs[i];
        DetectionMissingOnFrame::TaskOutput output = mergeSingleTaskResults(assignmentResults, i);

        tsResult.taskResults.push_back({input, output});
    }

    return tsResult;
}

void DetectionMissingOnFrame::evaluateAssignments(
    const io::TolokaClient& /*tolokaClient*/,
    const DetectionMissingOnFrame::TaskSuiteResult& /*tsResult*/)
{
    return;
}

} // toloka
} // mrc
} // maps
