{{>licenseInfo}}
{{#operations}}

#include "{{classname}}.h"
#include "{{prefix}}Helpers.h"

namespace {{apiNamespace}}
{

using namespace {{helpersNamespace}};
{{#hasModelImport}}
using namespace {{modelNamespace}};{{/hasModelImport}}

const std::string {{classname}}::base = "{{basePathWithoutHost}}";

{{classname}}::{{classname}}(const std::shared_ptr<Pistache::Rest::Router>& rtr)
    : ApiBase(rtr)
{
}

void {{classname}}::init() {
    setupRoutes();
}

void {{classname}}::setupRoutes() {
    using namespace Pistache::Rest;

    {{#operation}}
    Routes::{{httpMethod}}(*router, base + "{{{vendorExtensions.x-codegen-pistache-path}}}", Routes::bind(&{{classname}}::{{operationIdSnakeCase}}_handler, this));
    {{/operation}}

    // Default handler, called when a route is not found
    router->addCustomHandler(Routes::bind(&{{classname}}::{{classnameSnakeLowerCase}}_default_handler, this));
}

std::pair<Pistache::Http::Code, std::string> {{classname}}::handleParsingException(const std::exception& ex) const noexcept
{
    try {
        throw;
    } catch (nlohmann::detail::exception &e) {
        return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
    } catch ({{helpersNamespace}}::ValidationException &e) {
        return std::make_pair(Pistache::Http::Code::Bad_Request, e.what());
    } catch (std::exception &e) {
        return std::make_pair(Pistache::Http::Code::Internal_Server_Error, e.what());
    }
}

std::pair<Pistache::Http::Code, std::string> {{classname}}::handleOperationException(const std::exception& ex) const noexcept
{
    return std::make_pair(Pistache::Http::Code::Internal_Server_Error, ex.what());
}

{{#operation}}
void {{classname}}::{{operationIdSnakeCase}}_handler(const Pistache::Rest::Request &{{#hasParams}}request{{/hasParams}}, Pistache::Http::ResponseWriter response) {
    try {

    {{#vendorExtensions.x-codegen-pistache-is-parsing-supported}}
    {{#hasPathParams}}
    // Getting the path params
    {{#pathParams}}
    auto {{paramName}} = request.param(":{{paramName}}").as<{{dataType}}>();
    {{/pathParams}}
    {{/hasPathParams}}{{#hasBodyParam}}
    // Getting the body param
    {{#bodyParam}}
    {{^isPrimitiveType}}{{^isContainer}}
    {{baseType}} {{paramName}};{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}> {{paramName}};{{/isArray}}{{#isMap}}std::map<std::string, {{items.baseType}}> {{paramName}};{{/isMap}}{{/isPrimitiveType}}
    {{#isPrimitiveType}}
    {{dataType}} {{paramName}};
    {{/isPrimitiveType}}
    {{/bodyParam}}
    {{/hasBodyParam}}{{#hasQueryParams}}
    // Getting the query params
    {{#queryParams}}
    auto {{paramName}}Query = request.query().get("{{baseName}}");
    std::optional<{{^isContainer}}{{dataType}}{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}>{{/isArray}}> {{paramName}};
    if({{paramName}}Query.has_value()){
        {{^isContainer}}{{dataType}}{{/isContainer}}{{#isArray}}std::vector<{{items.baseType}}>{{/isArray}} valueQuery_instance;
        if(fromStringValue({{paramName}}Query.value(), valueQuery_instance)){
            {{paramName}} = valueQuery_instance;
        }
    }
    {{/queryParams}}
    {{/hasQueryParams}}{{#hasHeaderParams}}
    // Getting the header params
    {{#headerParams}}
    auto {{paramName}} = request.headers().tryGetRaw("{{baseName}}");
    {{/headerParams}}
    {{/hasHeaderParams}}

    try {
    {{#hasBodyParam}}
    {{#bodyParam}}
    {{^isPrimitiveType}}
        nlohmann::json::parse(request.body()).get_to({{paramName}});{{#isArray}}
        for (const auto& validationParam : {{paramName}})
             validationParam.validate();{{/isArray}}{{^isArray}}
        {{paramName}}.validate();{{/isArray}}
    {{/isPrimitiveType}}
    {{#isPrimitiveType}}
        {{paramName}} = request.body();
    {{/isPrimitiveType}}
    } catch (std::exception &e) {
        const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleParsingException(e);
        response.send(errorInfo.first, errorInfo.second);
        return;
    }

    try {
    {{/bodyParam}}
    {{/hasBodyParam}}
        this->{{operationIdSnakeCase}}({{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}response);
    {{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
    {{^vendorExtensions.x-codegen-pistache-is-parsing-supported}}
    try {
      this->{{operationIdSnakeCase}}(request, response);
    {{/vendorExtensions.x-codegen-pistache-is-parsing-supported}}
    } catch (Pistache::Http::HttpError &e) {
        response.send(static_cast<Pistache::Http::Code>(e.code()), e.what());
        return;
    } catch (std::exception &e) {
        const std::pair<Pistache::Http::Code, std::string> errorInfo = this->handleOperationException(e);
        response.send(errorInfo.first, errorInfo.second);
        return;
    }

    } catch (std::exception &e) {
        response.send(Pistache::Http::Code::Internal_Server_Error, e.what());
    }

}
{{/operation}}

void {{classname}}::{{classnameSnakeLowerCase}}_default_handler(const Pistache::Rest::Request &, Pistache::Http::ResponseWriter response) {
    response.send(Pistache::Http::Code::Not_Found, "The requested method does not exist");
}

} // namespace {{apiNamespace}}

{{/operations}}
