#include <VWeb.h>
#include <algorithm>


namespace VWeb {

#define stringify(name) {name, std::string(#name).replace(0,12,"")}
static std::unordered_map<HttpMethod, std::string> s_HttpMethodToString = {
    stringify(HttpMethod::HEAD),
    stringify(HttpMethod::GET),
    stringify(HttpMethod::OPTIONS),
    stringify(HttpMethod::POST),
    stringify(HttpMethod::PUT),
    stringify(HttpMethod::PATCH),
    stringify(HttpMethod::DELETE),
    stringify(HttpMethod::FALLBACK)
};
#undef stringify

Route::Route(std::initializer_list<HttpMethod> methods) {
  m_AllowedMethods = methods;
  m_AllowAll = false;
  m_AllowedMethods.push_back(HttpMethod::HEAD);
  m_AllowedMethods.push_back(HttpMethod::OPTIONS);
}
bool Route::Execute(Request &request, Response &response) {
  switch (request.Method) {
  case HttpMethod::GET:
  case HttpMethod::HEAD: return Get(request, response);
  case HttpMethod::POST: return Post(request, response);
  case HttpMethod::PUT: return Put(request, response);
  case HttpMethod::OPTIONS: return Options(request, response);
  case HttpMethod::PATCH: return Patch(request, response);
  case HttpMethod::DELETE: return Delete(request, response);
  default: return Fallback(request, response);
  }
}
bool Route::Get(Request &request, Response &response) {
  return true;
}
bool Route::Post(Request &request, Response &response) {
  return true;
}
bool Route::Put(Request &request, Response &response) {
  return true;
}
bool Route::Patch(Request &request, Response &response) {
  return true;
}
bool Route::Delete(Request &request, Response &response) {
  return true;
}
bool Route::Options(Request &request, Response &response) {
  std::stringstream str{};
  bool isFirst = true;
  if (m_AllowAll) {
    for (auto &[key, value] : s_HttpMethodToString) {
      if (!isFirst)
        str << ", ";
      str << value;
      isFirst = false;
    }
  } else {
    for (auto &method : m_AllowedMethods) {
      if (!isFirst)
        str << ", ";
      str << s_HttpMethodToString[method];
      isFirst = false;
    }
  }
  response.SetHeader("Allow", str.str());
  return true;
}
bool Route::Fallback(Request &request, Response &response) {
  return true;
}
bool Route::IsAllowed(Request &request) { return true; }
bool Route::SupportsMethod(Request &request) {
  return m_AllowAll ||
         std::find(m_AllowedMethods.begin(), m_AllowedMethods.end(),
                   request.Method) != m_AllowedMethods.end();
}
void Route::AllowMethod(HttpMethod method) {
  if (std::find(m_AllowedMethods.begin(), m_AllowedMethods.end(), method) == m_AllowedMethods.end())
    m_AllowedMethods.push_back(method);
}
} // namespace VWeb