/*
 * Licensed to Open Source Radio Access Network(OS-RAN) Alliance and OAI
 * Software Alliance under one or more contributor license agreements. The
 * initial OpenXG series projects are derided from OAI projects, the files from
 * OAI projects are all in compliance with OAI Public License, Version 1.1.
 * codes and files developed from OpenXG projects and from OS-RAN Alliance
 * are all under OS-RAN licenses; you may not use this file except in compliance
 * with the license.  You may get a copy of the license at:
 *	http://www.openxg.org.cn/?falu_69.html
 * For more information about OpenXG, please contact:
 * contact@openxg.org.cn
 */

#include "SMContextsCollectionApiImpl.h"
#include "logger.hpp"
#include "smf_msg.hpp"
#include "itti_msg_n11.hpp"
#include "3gpp_29.502.h"
#include <nghttp2/asio_http2_server.h>
#include "smf_config.hpp"
#include "3gpp_conversions.hpp"

extern smf::smf_config smf_cfg;

namespace oai {
namespace smf_server {
namespace api {

using namespace oai::smf_server::model;

SMContextsCollectionApiImpl::SMContextsCollectionApiImpl(
    std::shared_ptr<Pistache::Rest::Router> rtr, smf::smf_app* smf_app_inst,
    std::string address)
    : SMContextsCollectionApi(rtr),
      m_smf_app(smf_app_inst),
      m_address(address) {}

void SMContextsCollectionApiImpl::post_sm_contexts(
    const SmContextMessage& smContextMessage,
    Pistache::Http::ResponseWriter& response) {
  Logger::smf_api_server().info("PDU Session Create SM Context Request.");

  // Create a pdu_session_create_sm_context_request message and store
  // the necessary information
  Logger::smf_api_server().debug(
      "Create a pdu_session_create_sm_context_request message and store the "
      "necessary information");
  smf::pdu_session_create_sm_context_request sm_context_req_msg = {};

  // convert from SmContextMessage to pdu_session_create_sm_context_request
  xgpp_conv::sm_context_create_from_openapi(
      smContextMessage, sm_context_req_msg);

  // Set API Root to be used as location header in HTTP response
  sm_context_req_msg.set_api_root(
      m_address + base + smf_cfg.sbi_api_version +
      NSMF_PDU_SESSION_SM_CONTEXT_CREATE_URL);

  boost::shared_ptr<
      boost::promise<smf::pdu_session_create_sm_context_response> >
      p = boost::make_shared<
          boost::promise<smf::pdu_session_create_sm_context_response> >();
  boost::shared_future<smf::pdu_session_create_sm_context_response> f;
  f = p->get_future();

  // Generate ID for this promise (to be used in SMF-APP)
  uint32_t promise_id = generate_promise_id();
  Logger::smf_api_server().debug("Promise ID generated %d", promise_id);
  m_smf_app->add_promise(promise_id, p);

  // Handle the pdu_session_create_sm_context_request message in smf_app
  std::shared_ptr<itti_n11_create_sm_context_request> itti_msg =
      std::make_shared<itti_n11_create_sm_context_request>(
          TASK_SMF_SBI, TASK_SMF_APP, promise_id);
  itti_msg->req          = sm_context_req_msg;
  itti_msg->http_version = 1;
  m_smf_app->handle_pdu_session_create_sm_context_request(itti_msg);

  // Wait for the result from APP and send reply to AMF
  smf::pdu_session_create_sm_context_response sm_context_response = f.get();
  Logger::smf_api_server().debug("Got result for promise ID %d", promise_id);

  nlohmann::json json_data = {};

  response.headers().add<Pistache::Http::Header::Location>(
      sm_context_response.get_smf_context_uri());  // Location header
  sm_context_response.get_json_data(json_data);
  std::string json_format;
  sm_context_response.get_json_format(json_format);
  if (!json_data.empty()) {
    response.headers().add<Pistache::Http::Header::ContentType>(
        Pistache::Http::Mime::MediaType(json_format));
    response.send(
        Pistache::Http::Code(sm_context_response.get_http_code()),
        json_data.dump().c_str());
  } else {
    response.send(Pistache::Http::Code(sm_context_response.get_http_code()));
  }
}
}  // namespace api
}  // namespace smf_server
}  // namespace oai
