#include "server/api_server.hpp"

#include "util/http_util.hpp"

namespace lm {

void ApiServer::registerRobotRoutes(httplib::Server& svr)
{
  svr.Get("/api/robot/status", [this](const httplib::Request&, httplib::Response& res) {
    HttpUtil::addCors(res);
    robot_runtime_.tick();
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/start", [this](const httplib::Request&, httplib::Response& res) {
    HttpUtil::addCors(res);
    std::string err;
    if (!robot_runtime_.start(err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/pause", [this](const httplib::Request&, httplib::Response& res) {
    HttpUtil::addCors(res);
    std::string err;
    if (!robot_runtime_.pause(err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/errors/reset", [this](const httplib::Request&, httplib::Response& res) {
    HttpUtil::addCors(res);
    std::string err;
    if (!robot_runtime_.resetError(err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/cmd_vel", [this](const httplib::Request& req, httplib::Response& res) {
    HttpUtil::addCors(res);
    nlohmann::json body;
    try
    {
      body = nlohmann::json::parse(req.body);
    }
    catch (...)
    {
      return HttpUtil::jsonError(res, 400, "invalid JSON");
    }
    const double linear = body.value("linear", body.value("vx", 0.0));
    const double angular = body.value("angular", body.value("omega", 0.0));
    std::string err;
    if (!robot_runtime_.setCmdVel(linear, angular, err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/joystick", [this](const httplib::Request& req, httplib::Response& res) {
    HttpUtil::addCors(res);
    nlohmann::json body;
    try
    {
      body = nlohmann::json::parse(req.body);
    }
    catch (...)
    {
      return HttpUtil::jsonError(res, 400, "invalid JSON");
    }
    if (!body.contains("engaged") || !body["engaged"].is_boolean())
      return HttpUtil::jsonError(res, 400, "engaged (boolean) is required");
    const std::string speed = body.value("speed", "");
    std::string err;
    if (!robot_runtime_.setJoystick(body["engaged"].get<bool>(), speed, err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });

  svr.Post("/api/robot/active_map", [this](const httplib::Request& req, httplib::Response& res) {
    HttpUtil::addCors(res);
    nlohmann::json body;
    try
    {
      body = nlohmann::json::parse(req.body);
    }
    catch (...)
    {
      return HttpUtil::jsonError(res, 400, "invalid JSON");
    }
    const std::string map_id = body.value("map_id", "");
    if (map_id.empty())
      return HttpUtil::jsonError(res, 400, "map_id is required");
    if (!map_store_.find(map_id))
      return HttpUtil::jsonError(res, 404, "map not found");
    std::string err;
    if (!robot_runtime_.setActiveMap(map_id, err))
      return HttpUtil::jsonError(res, 400, err);
    res.set_header("Content-Type", "application/json; charset=utf-8");
    res.body = robot_runtime_.status().dump();
  });
}

}  // namespace lm
