#include "conduitclient.h"
#include "QtNetwork/QNetworkAccessManager"
#include <QtNetwork/QNetworkRequest>
#include <QUrlQuery>
#include <QJsonDocument>
#include <ctime>
#include <QEventLoop>
#include <QEventLoopLocker>
#include <QtNetwork/QNetworkReply>

QEventLoopLocker* lockerWaitingResponce = 0;

ConduitClient::~ConduitClient(){}

ConduitClient::ConduitClient(const QString& uri, const QString& user, const QString& token, const QString& certificate)
    : QObject(nullptr), m_URI(uri), m_user(user), m_conduitToken(token), m_certificate(certificate), m_manager(new QNetworkAccessManager()), m_loopWaitingResponce(new QEventLoop())
{
    connect(m_manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(replyReceived(QNetworkReply*)));
}

bool
ConduitClient::createSession()
{
    const QString token = QString("%1").arg(time(0));
    const QString signatureRaw =  token + m_certificate;
    QByteArray signatureHash = QCryptographicHash::hash(signatureRaw.toLatin1(), QCryptographicHash::Sha1);
    QString signatureHashLatin = QString::fromLatin1(signatureHash.toHex());
    QJsonObject query;
    query["authToken"]  = token;
    query["authSignature"] =signatureHashLatin;
    query["client"] = "juffed-client";
    query["clientVersion"] = "1";
    query["user"] = m_user;

    QJsonObject reply = requestRaw("conduit.connect", query);

  //Example:  "result\":{\"connectionID\":17,\"sessionKey\":\"l6jih3u7kxz3i624tewq2fvvmvmjiwzzp5ddicnk\"
    if (reply.contains("result")){
        QJsonObject sessionData = reply.find("result").value().toObject();

        if (sessionData.empty()) return false;
        m_SessionKey = sessionData["sessionKey"].toString();
        m_ConnectionID = sessionData["connectionID"].toInt();;
        return true;
    }

    return false;
}

QJsonObject
ConduitClient::request(const QString& method, const QJsonObject& json){
    if (m_SessionKey.isNull())   {
        if (!createSession()){
            return QJsonObject();
        }
    }

    QJsonObject metaQuery;
    metaQuery["sessionKey"] = m_SessionKey;
    metaQuery["connectionID"] = m_ConnectionID;
    metaQuery["token"] = m_conduitToken;

    QJsonObject query(json);
    query["__conduit__"] = metaQuery;

    return requestRaw(method, query);
}

void
ConduitClient::replyReceived(QNetworkReply* reply){
    m_serverReply = reply;

    delete lockerWaitingResponce;
    lockerWaitingResponce = 0;
}

QJsonObject
ConduitClient::requestRaw(const QString& method, const QJsonObject& json)
{
    QUrl requestUrl(m_URI + "/api/" + method);

    QUrlQuery query;
    query.addQueryItem("output", "json");
    query.addQueryItem("__conduit__", "true");
    query.addQueryItem("params", QJsonDocument(json).toJson(QJsonDocument::Compact));

    qDebug()<<requestUrl;
    qDebug()<<query.toString();

    QNetworkRequest request(requestUrl);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

    m_manager->post(request, query.toString(QUrl::FullyEncoded).replace("+", "%2B").toUtf8());
    lockerWaitingResponce = new QEventLoopLocker(m_loopWaitingResponce);
    m_loopWaitingResponce->exec();

    QString replyJson(m_serverReply->readAll());
    qDebug() << replyJson;
    delete m_serverReply;

    return QJsonDocument::fromJson(replyJson.toUtf8()).object();
}

//void
//ConduitClient::req
