#include <VWeb.h>

namespace VWeb {
// clang-format off
static std::unordered_map<HttpStatusCode, std::string> s_HTTPCodeToString = {
    {HttpStatusCode::Continue, "100 Continue"},
    {HttpStatusCode::SwitchingProtocols, "101 Switching Protocols"},
    {HttpStatusCode::Processing, "102 Processing"},
    {HttpStatusCode::EarlyHints, "103 Early Hints"},
    {HttpStatusCode::OK, "200 OK"},
    {HttpStatusCode::Created, "201 Created"},
    {HttpStatusCode::Accepted, "202 Accepted"},
    {HttpStatusCode::NonAuthoritativeInformation,"203 Non-Authoritative Information"},
    {HttpStatusCode::NoContent, "204 No Content"},
    {HttpStatusCode::ResetContent, "205 Reset Content"},
    {HttpStatusCode::PartialContent, "206 Partial Content"},
    {HttpStatusCode::MultiStatus, "207 Multi-Status"},
    {HttpStatusCode::AlreadyReported, "208 Already Reported"},
    {HttpStatusCode::IMUsed, "226 IM Used"},
    {HttpStatusCode::MultipleChoices, "300 Multiple Choices"},
    {HttpStatusCode::MovedPermanently, "301 Moved Permanently"},
    {HttpStatusCode::Found, "302 Found"},
    {HttpStatusCode::SeeOther, "303 See Other"},
    {HttpStatusCode::NotModified, "304 Not Modified"},
    {HttpStatusCode::UseProxy, "305 Use Proxy"},
    {HttpStatusCode::TemporaryRedirect, "307 Temporary Redirect"},
    {HttpStatusCode::PermanentRedirect, "308 Permanent Redirect"},
    {HttpStatusCode::BadRequest, "400 Bad Request"},
    {HttpStatusCode::Unauthorized, "401 Unauthorized"},
    {HttpStatusCode::PaymentRequired, "402 Payment Required"},
    {HttpStatusCode::Forbidden, "403 Forbidden"},
    {HttpStatusCode::NotFound, "404 Not Found"},
    {HttpStatusCode::MethodNotAllowed, "405 Method Not Allowed"},
    {HttpStatusCode::NotAcceptable, "406 Not Acceptable"},
    {HttpStatusCode::ProxyAuthenticationRequired,"407 Proxy Authentication Required"},
    {HttpStatusCode::RequestTimeout, "408 Request Timeout"},
    {HttpStatusCode::Conflict, "409 Conflict"},
    {HttpStatusCode::Gone, "410 Gone"},
    {HttpStatusCode::LengthRequired, "411 Length Required"},
    {HttpStatusCode::PreconditionFailed, "412 Precondition Failed"},
    {HttpStatusCode::PayloadTooLarge, "413 Payload Too Large"},
    {HttpStatusCode::URITooLong, "414 URI Too Long"},
    {HttpStatusCode::UnsupportedMediaType, "415 Unsupported Media Type"},
    {HttpStatusCode::RangeNotSatisfiable, "416 Range Not Satisfiable"},
    {HttpStatusCode::ExpectationFailed, "417 Expectation Failed"},
    {HttpStatusCode::ImATeapot, "418 I'm a teapot"},
    {HttpStatusCode::UnprocessableEntity, "422 Unprocessable Entity"},
    {HttpStatusCode::Locked, "423 Locked"},
    {HttpStatusCode::FailedDependency, "424 Failed Dependency"},
    {HttpStatusCode::UpgradeRequired, "426 Upgrade Required"},
    {HttpStatusCode::PreconditionRequired, "428 Precondition Required"},
    {HttpStatusCode::TooManyRequests, "429 Too Many Requests"},
    {HttpStatusCode::RequestHeaderFieldsTooLarge,"431 Request Header Fields Too Large"},
    {HttpStatusCode::UnavailableForLegalReasons,"451 Unavailable For Legal Reasons"},
    {HttpStatusCode::InternalServerError, "500 Internal Server Error"},
    {HttpStatusCode::NotImplemented, "501 Not Implemented"},
    {HttpStatusCode::BadGateway, "502 Bad Gateway"},
    {HttpStatusCode::ServiceUnavailable, "503 Service Unavailable"},
    {HttpStatusCode::GatewayTimeout, "504 Gateway Time-out"},
    {HttpStatusCode::HTTPVersionNotSupported, "505 HTTP Version Not Supported"},
    {HttpStatusCode::VariantAlsoNegotiates, "506 Variant Also Negotiates"},
    {HttpStatusCode::InsufficientStorage, "507 Insufficient Storage"},
    {HttpStatusCode::LoopDetected, "508 Loop Detected"},
    {HttpStatusCode::NotExtended, "510 Not Extended"},
    {HttpStatusCode::NetworkAuthenticationRequired,"511 Network Authentication Required"}
};
// clang-format on

Ref<Response> Response::FromCode(HttpStatusCode code) {
  auto response = CreateRef<Response>();
  response->SetStatus(code);
  return response;
}

std::string Response::GetResponse() {
  std::string content = m_Content.str();
  auto headData = TransformHeaders(content);

  auto outContent = std::string(headData + content);
  Length = content.length();
  return outContent;
}
void Response::SetHeader(const std::string &key, const std::string &value) {
  m_Headers[key].Set(value);
}
void Response::SetHeader(const std::string &key, ParameterValue &value) {
  m_Headers[key] = value;
}
void Response::AddHeaders(const std::string &key,
                          const Vector<std::string> &values) {
  auto &element = m_Headers[key];
  for (const auto &value : values)
    element.Add(value);
}
void Response::AddHeader(const std::string &key, const std::string &value) {
  m_Headers[key].Add(value);
}
void Response::SetType(const std::string &type) { m_Type = type; }
void Response::AddContent(const std::string &data) { m_Content << data; }
void Response::SetStatus(HttpStatusCode statusCode) { Status = statusCode; }
void Response::SetMethod(HttpMethod method) { Method = method; }

void Response::Reset() {
  m_Content = {};
}

std::string Response::TransformHeaders(const std::string &content) {
  std::ostringstream stream;
  stream << "HTTP/1.1 " << s_HTTPCodeToString[Status] << "\n";
  stream << "content-type: " << m_Type << "\n";
  stream << "content-length: " << content.length() << "\n";
  for (auto &[key, value] : m_Headers) {
    for (auto &val : value.Values()) {
      stream << key << ": " << val << "\n";
    }
  }
  stream << CookieData->TransformToHeader();
  stream << "\n";
  return stream.str();
}
} // namespace VWeb