#pragma once

#include "magic_strings.h"
#include "observers.h"
#include "yacare_helpers.h"

#include <maps/wikimap/mapspro/libs/controller/include/exception_info.h>
#include <maps/wikimap/mapspro/services/editor/src/actions/controller_async.h>
#include <maps/wikimap/mapspro/services/editor/src/serialize/formatter.h>
#include <maps/libs/log8/include/log8.h>


maps::wiki::controller::ExceptionInfo
handleControllerError(maps::wiki::common::FormatType formatType, maps::wiki::Profile* profile);

template <typename ControllerType>
void
handleController(yacare::Response& response, ControllerType& controller, maps::wiki::common::FormatType formatType)
{
    auto formatter = maps::wiki::Formatter::create(formatType);
    try {
        auto result = (*formatter)(*controller());
        DEBUG() << "RESULT: " << result;
        response << result;
    } catch (...) {
        wrapError(response, handleControllerError(formatType, &controller.profile()));
    }
    response[maps::wiki::HTTP_HEADER_CONTENT_TYPE] = httpContentType(formatType);
}

/**
 * Helper function for sending binary responses
 */
template <typename ControllerType>
void
handleBinaryController(yacare::Response& response, const typename ControllerType::Request& controllerRequest, maps::wiki::common::FormatType formatType)
{
    ControllerType controller(controllerRequest);
    try{
        auto result = controller();
        response[maps::wiki::HTTP_HEADER_CONTENT_TYPE] = result->contentType;
        response[maps::wiki::HTTP_HEADER_CONTENT_DISPOSITION] = result->contentDisposition;
        response << result->decodedData;
    } catch(...) {
        wrapError(response, handleControllerError(formatType, &controller.profile()));
        response[maps::wiki::HTTP_HEADER_CONTENT_TYPE] = httpContentType(formatType);
    }
}

template <typename ControllerType>
void
handleController(yacare::Response& response, const typename ControllerType::Request& controllerRequest, maps::wiki::common::FormatType formatType)
{
    ControllerType controller(controllerRequest);
    handleController(response, controller, formatType);
}

template <typename ControllerType>
void
handleController(
    yacare::Response& response,
    bool sync,
    const typename ControllerType::Request& controllerRequest,
    maps::wiki::common::FormatType formatType,
    maps::wiki::AsyncBaseController::WaitPolicy waitPolicy = maps::wiki::AsyncBaseController::WaitPolicy::Timeout)
{
    if (sync) {
        ControllerType controller(
            maps::wiki::observers(),
            controllerRequest);
        handleController(response, controller, formatType);
    } else {
        maps::wiki::ControllerAsync<ControllerType> controller(
            maps::wiki::observers(),
            controllerRequest,
            formatType,
            waitPolicy);
        handleController(response, controller, formatType);
    }
}
