#include <yandex/maps/mrc/toloka_client/task_suite.h>
#include <maps/libs/json/include/builder.h>
#include "task_suite_impl.h"
#include "magic_strings.h"

#include <utility>

namespace maps {
namespace mrc {
namespace toloka {
namespace io {

COPYABLE_PIMPL_DEFINITIONS(TaskSuiteItem)

TaskSuiteItem::TaskSuiteItem()
    : impl_(new Impl())
{
}

TaskSuiteItem TaskSuiteItem::fromJson(const json::Value& value)
{
    TaskSuiteItem task;
    if (value.hasField(FIELD_ID)) {
        task.setId(value[FIELD_ID].as<std::string>());
    }
    if (value.hasField(FIELD_INPUT_VALUES)) {
        task.setInputValues(value[FIELD_INPUT_VALUES]);
    }
    if (value.hasField(FIELD_KNOWN_SOLUTIONS)) {
        KnownSolutions knownSolutions;
        for (const auto& ks : value[FIELD_KNOWN_SOLUTIONS]) {
            knownSolutions.emplace_back(
                ks[FIELD_OUTPUT_VALUES],
                ks[FIELD_CORRECTNESS_WEIGHT].as<double>()
            );
        }
        task.setKnownSolutions(std::move(knownSolutions));
    }
    if (value.hasField(FIELD_MESSAGE_ON_UNKNOWN_SOLUTION)) {
        task.setMessageOnUnknownSolution(
            value[FIELD_MESSAGE_ON_UNKNOWN_SOLUTION].as<std::string>()
        );
    }
    return task;
}

TaskSuiteItem TaskSuiteItem::fromInputValues(json::Value inputValues)
{
    TaskSuiteItem task;
    task.setInputValues(std::move(inputValues));
    return task;
}


const std::string& TaskSuiteItem::id() const
{
    return impl_->id_;
}

const json::Value& TaskSuiteItem::inputValues() const
{
    return impl_->inputValues_;
}

const KnownSolutions& TaskSuiteItem::knownSolutions() const
{
    return impl_->knownSolutions_;
}

const std::string& TaskSuiteItem::messageOnUnknownSolution() const
{
    return impl_->messageOnUnknownSolution_;
}

TaskSuiteItem& TaskSuiteItem::setId(std::string id)
{
    impl_->id_ = std::move(id);
    return *this;
}

TaskSuiteItem& TaskSuiteItem::setInputValues(json::Value inputValues)
{
    impl_->inputValues_ = std::move(inputValues);
    return *this;
}

TaskSuiteItem& TaskSuiteItem::setKnownSolutions(KnownSolutions knownSolutions)
{
    impl_->knownSolutions_ = std::move(knownSolutions);
    return *this;
}

TaskSuiteItem& TaskSuiteItem::setMessageOnUnknownSolution(std::string message)
{
    impl_->messageOnUnknownSolution_ = std::move(message);
    return *this;
}

COPYABLE_PIMPL_DEFINITIONS(TaskSuiteCreationParams)

TaskSuiteCreationParams::TaskSuiteCreationParams(
    std::string poolId,
    TaskSuiteItems items)
        : impl_(new Impl(std::move(poolId), std::move(items)))
{
}

TaskSuiteCreationParams& TaskSuiteCreationParams::setOverlap(size_t overlap)
{
    impl_->overlap_ = overlap;
    return *this;
}


COPYABLE_PIMPL_DEFINITIONS(TaskSuite)

const std::string& TaskSuite::id() const { return impl_->id_; }

const std::string& TaskSuite::poolId() const { return impl_->poolId_; }

chrono::TimePoint TaskSuite::createdAt() const { return impl_->createdAt_; }

const TaskSuiteItems& TaskSuite::tasks() const { return impl_->tasks_; }

size_t TaskSuite::overlap() const { return impl_->overlap_; }



std::ostream& operator<<(std::ostream& os, const TaskSuiteCreationParams& params)
{
    return os << params.impl_->toJson();
}

std::ostream& operator<<(std::ostream& os,
                         const std::vector<TaskSuiteCreationParams>& paramsVec)
{
    json::Builder builder(os);
    builder << [&](json::ArrayBuilder b) {
        for (const auto& params : paramsVec) {
            b << [&](json::ObjectBuilder tsBuilder) {
                params.impl_->toJson(tsBuilder);
            };
        }
    };
    return os;
}

MOVABLE_PIMPL_DEFINITIONS(TaskSuitesResponse)

const TaskSuites& TaskSuitesResponse::taskSuites() const {
    return impl_->taskSuites_;
}

bool TaskSuitesResponse::hasMore() const { return impl_->hasMore_; }


MOVABLE_PIMPL_DEFINITIONS(TaskSuitesPostResponse)

const std::map<size_t, TaskSuite> TaskSuitesPostResponse::taskSuites() const
{
    return impl_->taskSuites_;
}

const std::map<size_t, json::Value> TaskSuitesPostResponse::errors() const
{
    return impl_->errors_;
}


} // namespace io
} // namespace toloka
} // namespace mrc
} // namespace maps

