#include "include/Extensions/extension.h"

#include "include/notepadqq.h"

#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QRandomGenerator>
#include <QTextStream>
#include <QTime>

namespace Extensions {

Extension::Extension(QString path, QString serverSocketPath)
    : QObject(0)
{
    m_extensionId = path + "-" + QString::number(QTime::currentTime().msec()) + "-" +
                    QString::number(QRandomGenerator::global()->generate());

    QJsonObject manifest = getManifest(path);

    if (!manifest.isEmpty()) {
        m_name = manifest.value("name").toString();

        if (m_name.isEmpty()) {
            failedToLoadExtension(path, tr("name missing or invalid"));
            return;
        }

        m_runtime = manifest.value("runtime").toString().toLower();
        QString main = manifest.value("main").toString();

        if (m_runtime == "nodejs") {
            process = new QProcess(this);
            process->setProcessChannelMode(QProcess::ForwardedChannels);
            process->setWorkingDirectory(path);

            QStringList args;
            args << "--harmony-proxies";
            args << main;
            args << serverSocketPath;
            args << m_extensionId;

            QString runtimePath = Notepadqq::nodejsPath();

            connect(process, &QProcess::errorOccurred, this, &Extension::on_processError);

            process->start(runtimePath, args);
        }

    } else {
        failedToLoadExtension(path, tr("unable to read nqq-manifest.json"));
        return;
    }

    // FIXME Load editor parts
    /*QFile fUi(path + "/ui.js");
    if (fUi.open(QFile::ReadOnly | QFile::Text)) {


    } else {
        failedToLoadExtension(path, "ui.js missing");
        return;
    }*/
}

QJsonObject Extension::getManifest(const QString& extensionPath)
{
    QFile fManifest(extensionPath + "/nqq-manifest.json");
    if (fManifest.open(QFile::ReadOnly | QFile::Text)) {
        QTextStream in(&fManifest);
        QString content = in.readAll();
        fManifest.close();

        QJsonParseError err;
        QJsonDocument manifestDoc = QJsonDocument::fromJson(content.toUtf8(), &err);

        if (err.error != QJsonParseError::NoError) {
            return QJsonObject();
        }

        return manifestDoc.object();

    } else {
        return QJsonObject();
    }
}

void Extension::on_processError(QProcess::ProcessError error)
{
    if (error == QProcess::FailedToStart) {
        failedToLoadExtension(m_name, tr("failed to start. Check your runtime: %1").arg(m_runtime));
    } else if (error == QProcess::Crashed) {
        qWarning() << QString("%1 crashed.").arg(m_name).toStdWString().c_str();
    }
}

void Extension::failedToLoadExtension(QString path, QString reason)
{
    // FIXME Mark extension as broken
    qWarning() << tr("Failed to load %1: %2").arg(path).arg(reason).toStdString().c_str();
}

QString Extension::id() const
{ return m_extensionId; }

QString Extension::name() const
{ return m_name; }

} // namespace Extensions
