// SPDX-FileCopyrightText: 2023 g10 code GmbH
// SPDX-Contributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "emailcontroller.h"

#include <QEventLoop>
#include <QHttpServerRequest>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QPromise>
#include <QUuid>
#include <utils.h>

#include "http_debug.h"
#include "webserver.h"

using namespace Qt::Literals::StringLiterals;

QHttpServerResponse EmailController::abstractEmailAction(const QHttpServerRequest &request, const QString &action, QHttpServerRequest::Method method)
{
    const auto client = checkAuthentification(request);
    if (!client) {
        return forbidden();
    }

    QNetworkRequest viewEmailRequest(QUrl(u"http://127.0.0.1:"_s + QString::number(client->port) + u'/' + action));
    viewEmailRequest.setHeader(QNetworkRequest::ContentTypeHeader, u"application/json"_s);
    auto email = Utils::findHeader(request.headers(), "X-EMAIL");
    auto displayName = Utils::findHeader(request.headers(), "X-NAME");
    auto token = QUuid::createUuid().toString(QUuid::WithoutBraces).toUtf8();
    viewEmailRequest.setRawHeader("X-EMAIL", email);
    viewEmailRequest.setRawHeader("X-TOKEN", token);
    viewEmailRequest.setRawHeader("X-NAME", displayName);

    auto &serverState = ServerState::instance();
    serverState.composerRequest[token] = QString::fromUtf8(email);

    auto &state = ServerState::instance();
    QNetworkReply *reply;
    if (method == QHttpServerRequest::Method::Post) {
        const auto body = request.body();
        reply = state.qnam.post(viewEmailRequest, body);
    } else {
        reply = state.qnam.deleteResource(viewEmailRequest);
    }

    QObject::connect(reply, &QNetworkReply::finished, reply, [reply]() {
        if (reply->error() != QNetworkReply::NoError) {
            qCWarning(HTTP_LOG) << reply->error() << reply->errorString();
        }
    });

    return QHttpServerResponse(QJsonObject{
        {"status"_L1, "ok"_L1},
    });
}

QHttpServerResponse EmailController::viewEmailAction(const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    return abstractEmailAction(request, u"view"_s);
}

QHttpServerResponse EmailController::newEmailAction(const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    return abstractEmailAction(request, u"new"_s);
}

QHttpServerResponse EmailController::draftAction(QString, const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post && request.method() != QHttpServerRequest::Method::Delete) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    return abstractEmailAction(request, request.url().path(), request.method());
}

QHttpServerResponse EmailController::replyEmailAction(const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    return abstractEmailAction(request, u"reply"_s);
}

QHttpServerResponse EmailController::forwardEmailAction(const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    return abstractEmailAction(request, u"forward"_s);
}

QHttpServerResponse checkStatus(int port, const QByteArray &body)
{
    QNetworkRequest infoEmailRequest(QUrl(u"http://127.0.0.1:"_s + QString::number(port) + u"/info"_s));
    infoEmailRequest.setHeader(QNetworkRequest::ContentTypeHeader, u"application/json"_s);

    auto &state = ServerState::instance();
    QEventLoop eventLoop;
    auto reply = state.qnam.post(infoEmailRequest, body);
    QObject::connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
    eventLoop.exec();

    QJsonParseError error;
    const auto resultBody = QJsonDocument::fromJson(reply->readAll(), &error);
    if (resultBody.isNull()) {
        return QHttpServerResponse(QHttpServerResponse::StatusCode::BadRequest);
    }

    if (!resultBody.isObject()) {
        return QHttpServerResponse(QHttpServerResponse::StatusCode::BadRequest);
    }

    return QHttpServerResponse{resultBody.object()};
}

QHttpServerResponse EmailController::infoEmailAction(const QHttpServerRequest &request)
{
    if (request.method() != QHttpServerRequest::Method::Post) {
        return badRequest(u"Endpoint only supports POST request"_s);
    }

    const auto server = checkAuthentification(request);
    if (!server) {
        return forbidden();
    }

    return checkStatus(server->port, request.body());
}

QHttpServerResponse EmailController::socketWebAction(const QHttpServerRequest &request, WebServer *webServer)
{
    const auto email = QString::fromUtf8(Utils::findHeader(request.headers(), "X-EMAIL"));
    const auto token = Utils::findHeader(request.headers(), "X-TOKEN");
    const auto &serverState = ServerState::instance();

    if (serverState.composerRequest[token] != email) {
        return forbidden();
    }

    webServer->sendMessageToWebClient(email, request.body());

    return QHttpServerResponse(QJsonObject{
        {"status"_L1, "OK"_L1},
    });
}
