#include "request.h"

#include <maps/libs/json/include/value.h>
#include <maps/libs/log8/include/log8.h>
#include <yandex/maps/mrc/toloka_client/assignment.h>
#include <yandex/maps/mrc/toloka_client/filter.h>
#include <yandex/maps/mrc/toloka_client/task_suite.h>

namespace maps {
namespace mrc {
namespace toloka {

namespace {

const size_t BATCH_SIZE = 20;

const std::string FIELD_BBOX = "bbox";
const std::string FIELD_PROBLEM = "problem";
const std::string FIELD_SIGN_ID = "sign_id";
const std::string FIELD_IMAGE = "image";

Bbox bboxFromJson(const json::Value& jsonBbox)
{
    REQUIRE(jsonBbox.isArray() && jsonBbox.size() == 2,
            "Bad bbox coordinates count");
    auto p1 = jsonBbox[0];
    auto p2 = jsonBbox[1];
    REQUIRE(p1.isArray() && p1.size() == 2, "Bad coordinate format");
    REQUIRE(p2.isArray() && p2.size() == 2, "Bad coordinate format");
    auto x1 = p1[0].as<double>();
    auto y1 = p1[1].as<double>();
    auto x2 = p2[0].as<double>();
    auto y2 = p2[1].as<double>();
    return Bbox(geolib3::Point2(x1, y1), geolib3::Point2(x2, y2));
}


std::vector<TaskInput> getInputValues(const io::TaskSuiteItems& items)
{
    std::vector<TaskInput> taskInputs;
    for (const auto& item : items) {
        auto source = item.inputValues()[FIELD_IMAGE].as<std::string>();
        Bbox bbox;
        bbox = bboxFromJson(item.inputValues()[FIELD_BBOX]);
        taskInputs.push_back(TaskInput(std::move(source), std::move(bbox)));
    }
    return taskInputs;
}

std::vector<TaskOutput> getOutputValues(const io::AssignmentSolutions& items)
{
    std::vector<TaskOutput> taskOutputs;

    for (const auto& item : items) {
        const auto& ov = item.outputValues();

        TaskAnswer answer = parseTaskAnswer(ov[FIELD_PROBLEM].as<std::string>());

        std::string signId;
        if (ov.hasField(FIELD_SIGN_ID) && !ov[FIELD_SIGN_ID].isNull()) {
            signId = ov[FIELD_SIGN_ID].as<std::string>();
        }
        taskOutputs.emplace_back(answer, signId);
    }
    return taskOutputs;
}

bool isAssignmentFinished(const io::Assignment& assignment)
{
    // Exclude Active, Skipped and Expired assignments
    return assignment.status() == io::AssignmentStatus::Submitted ||
           assignment.status() == io::AssignmentStatus::Accepted ||
           assignment.status() == io::AssignmentStatus::Rejected;
}

} // anonymous namespace

IdToTaskSuite loadTaskSuites(const io::TolokaClient& tolokaClient,
                             const std::string& poolId)
{
    INFO() << "Loading task suites";
    IdToTaskSuite resultMap;
    io::Filter filter;
    filter.byPoolId(poolId);
    auto resp = tolokaClient.getTaskSuites(std::move(filter));

    for (const auto& ts : resp.taskSuites()) {
        TaskSuite taskSuite;
        taskSuite.id = ts.id();
        taskSuite.poolId = ts.poolId();
        taskSuite.overlap = ts.overlap();
        taskSuite.tasks = getInputValues(ts.tasks());
        resultMap.emplace(ts.id(), std::move(taskSuite));
    }
    return resultMap;
}

TaskSuiteIdToResults
loadTaskSuitesResults(const io::TolokaClient& tolokaClient,
                      const std::string& poolId)
{
    INFO() << "Loading task suite results";
    TaskSuiteIdToResults resultMap;
    io::Filter filter;
    filter.byPoolId(poolId);
    auto resp = tolokaClient.getAssignments(std::move(filter));

    for (const auto& assignment : resp.assignments()) {
        // Keep only the assignments which have output values,
        // i.e. skip Active/Skipped/Expired assignments
        if (!isAssignmentFinished(assignment)) {
            continue;
        }

        AssignmentResult result;
        result.taskSuiteId = assignment.taskSuiteId();
        result.assignmentId = assignment.id();
        result.status = assignment.status();
        result.userId = assignment.userId();
        result.inputs = getInputValues(assignment.tasks());
        result.outputs = getOutputValues(assignment.solutions());

        resultMap[assignment.taskSuiteId()].push_back(std::move(result));
    }
    return resultMap;
}

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

