#include "include/Extensions/extensionsserver.h"

#include <QJsonDocument>
#include <QLocalSocket>
#include <QMessageBox>

namespace Extensions {

ExtensionsServer::ExtensionsServer(QSharedPointer<RuntimeSupport> extensionsRTS, QObject* parent)
    : QObject(parent)
    , m_extensionsRTS(extensionsRTS)
{
}

ExtensionsServer::~ExtensionsServer() {}

bool ExtensionsServer::startServer(QString name)
{
    QLocalServer::removeServer(name);

    m_server = new QLocalServer(this);
    if (!m_server->listen(name)) {
        qCritical() << QString("Unable to start extensions server %1. Extensions will not be loaded.")
                           .arg(name)
                           .toStdString()
                           .c_str();

        return false;
    }

    connect(m_server, &QLocalServer::newConnection, this, &ExtensionsServer::on_newConnection);
    return true;
}

QString ExtensionsServer::socketPath()
{
    if (m_server->isListening()) {
        return m_server->fullServerName();
    } else {
        return QString();
    }
}

void ExtensionsServer::on_newConnection()
{
    QLocalSocket* client = m_server->nextPendingConnection();
    if (client != nullptr) {
        m_sockets.append(client);

        connect(client, &QLocalSocket::readyRead, this, [=, this] { on_clientMessage(client); });
        connect(client, &QLocalSocket::disconnected, this, [=, this] { on_socketDisconnected(client); });

        sendMessage(client, m_extensionsRTS->getCurrentExtensionStartedEvent());
    }
}

void ExtensionsServer::on_clientMessage(QLocalSocket* socket)
{
    QTextStream stream(socket);

    if (stream.atEnd())
        return;

    while (1) {
        QString jsonRequest = stream.readLine();
        if (jsonRequest.isNull())
            break;

        QJsonDocument request = QJsonDocument::fromJson(jsonRequest.toUtf8());

        QJsonObject response = m_extensionsRTS->handleRequest(request.object());
        QString jsonResponse = QString(QJsonDocument(response).toJson(QJsonDocument::Compact)).trimmed();

        stream << jsonResponse << "\n";
    }
}

void ExtensionsServer::on_socketDisconnected(QLocalSocket* socket)
{
    m_sockets.removeAll(socket);
    socket->deleteLater();
    Q_ASSERT(m_sockets.contains(socket) == false);
}

void ExtensionsServer::broadcastMessage(const QJsonObject& message)
{
    QString jsonMessage = QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).trimmed();

    for (QLocalSocket* socket : m_sockets) {
        if (socket->isOpen()) {
            QTextStream stream(socket);
            stream << jsonMessage << "\n";
        }
    }
}

void ExtensionsServer::sendMessage(QLocalSocket* socket, const QJsonObject& message)
{
    if (socket->isOpen()) {
        QString jsonMessage = QString(QJsonDocument(message).toJson(QJsonDocument::Compact)).trimmed();

        QTextStream stream(socket);
        stream << jsonMessage << "\n";
    }
}

QSharedPointer<RuntimeSupport> ExtensionsServer::runtimeSupport()
{ return m_extensionsRTS; }
} // namespace Extensions
