#include "common.h"
#include "fixture.h"

#include <maps/infra/yacare/include/test_utils.h>
#include <maps/libs/chrono/include/time_point.h>
#include <maps/libs/http/include/http.h>
#include <maps/libs/http/include/test_utils.h>
#include <maps/libs/json/include/std/vector.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/gateway.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/task.h>
#include <maps/wikimap/mapspro/services/mrc/libs/db/include/ugc/tasks_group_gateway.h>
#include <maps/libs/geolib/include/conversion.h>
#include <maps/libs/geolib/include/serialization.h>
#include <maps/libs/geolib/include/test_tools/comparison.h>

#include <boost/lexical_cast.hpp>

namespace maps {
namespace mrc {
namespace tasks_planner {
namespace tests {

TEST(tasks_api_should, test_get_all_tasks)
{
    Fixture fixture;
    auto tasksGroup1 = fixture.createTasksGroup();
    auto task1 = fixture.createTask(tasksGroup1.id());

    http::MockRequest request(
        http::GET,
        http::URL("http://localhost/tasks/")
            .addParam("lang", "ru_RU")
    );

    auto response = yacare::performTestRequest(request);
    EXPECT_EQ(response.status, 200);

    auto responseSchema = readResponseSchemasFromSwagger(schemasPath());
    validateJson(response.body,
                 responseSchema.at({"GET", "/tasks/", 200}),
                 schemasDir());
}

TEST(tasks_api_should, test_get_tasks_with_assignments)
{
    Fixture fixture;
    auto tasksGroup = fixture.createTasksGroup();
    auto task = fixture.createTask(tasksGroup.id());
    auto assignment = fixture.createAssignment(task, "123");


    http::MockRequest request(
        http::GET,
        http::URL("http://localhost/tasks/")
            .addParam("lang", "ru_RU")
            .addParam("with_assignment", "true")
    );

    auto response = yacare::performTestRequest(request);
    EXPECT_EQ(response.status, 200);

    auto responseSchema = readResponseSchemasFromSwagger(schemasPath());
    auto body = response.body;
    validateJson(body,
                 responseSchema.at({"GET", "/tasks/", 200}),
                 schemasDir());
    auto responseJson = json::Value::fromString(body);
    auto assignmentJson = responseJson[0]["assignment"];
    EXPECT_EQ(assignmentJson["id"].as<std::string>(), std::to_string(assignment.id()));
}

TEST(tasks_api_should, test_get_task_by_id)
{
    Fixture fixture;
    auto tasksGroup1 = fixture.createTasksGroup();
    auto task1 = fixture.createTask(tasksGroup1.id());


    http::MockRequest request(
        http::GET,
        http::URL("http://localhost/tasks/" + std::to_string(task1.id()) + "/")
            .addParam("lang", "ru_RU")
    );

    auto response = yacare::performTestRequest(request);
    EXPECT_EQ(response.status, 200);

    auto responseSchema = readResponseSchemasFromSwagger(schemasPath());
    auto body = response.body;
    validateJson(body,
                 responseSchema.at({"GET", "/tasks/{id}/", 200}),
                 schemasDir());

    auto bodyJson = json::Value::fromString(body);
    EXPECT_THAT(bodyJson["cameraDirections"].as<std::vector<std::string>>(),
                testing::ContainerEq(std::vector<std::string>{"Front"}));
}

TEST(tasks_api_should, test_patch_task_by_id)
{
    Fixture fixture;
    auto tasksGroup1 = fixture.createTasksGroup();
    auto task1 = fixture.createTask(tasksGroup1.id());


    http::MockRequest request(
        http::PATCH,
        http::URL("http://localhost/tasks/" + std::to_string(task1.id()) + "/")
            .addParam("lang", "ru_RU")
    );
    request.body = "{\"status\":\"Closed\"}";

    auto response = yacare::performTestRequest(request);
    EXPECT_EQ(response.status, 200);

    auto responseSchema = readResponseSchemasFromSwagger(schemasPath());
    validateJson(response.body,
                 responseSchema.at({"PATCH", "/tasks/{id}/", 200}),
                 schemasDir());

    auto txn = fixture.txnHandle();
    db::ugc::TaskGateway gtw(*txn);
    auto modifiedTask = gtw.loadById(task1.id());
    gtw.loadNames(modifiedTask);;
    EXPECT_EQ(modifiedTask.status(), db::ugc::TaskStatus::Done);
}

TEST(tasks_api_should, test_get_task_targets)
{
    Fixture fixture;
    auto tasksGroup1 = fixture.createTasksGroup();
    auto task1 = fixture.createTask(tasksGroup1.id());


    http::MockRequest request(
        http::GET,
        http::URL("http://localhost/tasks/" + std::to_string(task1.id()) + "/targets/")
    );

    auto response = yacare::performTestRequest(request);
    EXPECT_EQ(response.status, 200);

    auto responseSchema = readResponseSchemasFromSwagger(schemasPath());
    validateJson(response.body,
                 responseSchema.at({"GET", "/tasks/{id}/targets/", 200}),
                 schemasDir());
}

} // namespace tests
} // namespace tasks_planner
} // namespace mrc
} // namespace maps
