#include "updater.h"
#include <QJsonValue>
#include <QJsonObject>
#include <QJsonDocument>

#include "downloadmanager.h"
#include "util/networkagent.h"

Updater::Updater(const QString &url, const QString &version, bool autoUpgrade, int autoUpgradeInterval, QObject *parent):
    QObject(parent),
    m_url(url),
    m_currentVersion(version)
{
    m_autoUpgradeInterval = autoUpgradeInterval;
    m_autoUpgrade = autoUpgrade;
    m_updateTimer = new QTimer(this);
    m_updateTimer->setInterval(autoUpgradeInterval >= 3600 * 1000 ? autoUpgradeInterval : 3600 * 1000);

    connect(m_updateTimer, &QTimer::timeout, this, [ = ] {
        checkForUpdate();
    });

    createNetworkAccessManager();
    m_downloadManager = new DownloadManager(this);
    connect(m_downloadManager, &DownloadManager::finished, this, &Updater::downloadFinished);

    QTimer::singleShot(1000 * 5, [ = ] {
        checkForUpdate();
        m_updateTimer->start();
    });
}

void Updater::createNetworkAccessManager()
{
    if (m_manager) {
        disconnect(m_manager, &QNetworkAccessManager::finished, this, &Updater::onReply);
        m_manager->deleteLater();
    }
    m_manager = new QNetworkAccessManager(this);
    connect(m_manager, &QNetworkAccessManager::finished, this, &Updater::onReply);
}

QString Updater::url() const
{
    return m_url;
}

void Updater::setUrl(const QString &url)
{
    m_url = url;
}

void Updater::checkForUpdate()
{
    qDebug() << "check autoUpgrade:" << m_autoUpgrade << m_autoUpgradeInterval;
    if (!m_autoUpgrade) {
        return;
    }

    if (!url().isEmpty()) {
        createNetworkAccessManager();
        auto platformUrl = url() + "/" + NetworkAgent::instance()->clientPlatform();
        auto request = NetworkAgent::instance()->createRequest(platformUrl);
        m_manager->get(request);
    }
}

void Updater::onReply(QNetworkReply *reply)
{
    QUrl redirect = reply->attribute(
                        QNetworkRequest::RedirectionTargetAttribute).toUrl();
    if (!redirect.isEmpty()) {
        setUrl(redirect.toString());
        checkForUpdate();
        return;
    }

    /* There was a network error */
    if (reply->error() != QNetworkReply::NoError) {
        setUpdateAvailable(false);
        return;
    }

    /* Try to create a JSON document from downloaded data */
    QJsonDocument document = QJsonDocument::fromJson(reply->readAll());

    /* JSON is invalid */
    if (document.isNull()) {
        setUpdateAvailable(false);
        return;
    }

    QJsonObject obj = document.object();
    qDebug() << obj;
    m_downloadUrl = obj.value("url").toString();
    m_latestVersion = obj.value("version").toString();

    m_updateAvailable = compareVersion(m_latestVersion, m_currentVersion);
    qDebug() << "current version" << m_currentVersion;
    if (m_updateAvailable) {
        qDebug() << "There is a new version: " << m_latestVersion;
        m_downloadManager->doDownload(QUrl(m_downloadUrl));
    } else {
        qDebug() << "latest version: " << m_latestVersion;
    }
}

QString Updater::currentVersion() const
{
    return m_currentVersion;
}

void Updater::setCurrentVersion(const QString &currentVersion)
{
    m_currentVersion = currentVersion;
}

bool Updater::updateAvailable() const
{
    return m_updateAvailable;
}

void Updater::setUpdateAvailable(bool updateAvailable)
{
    m_updateAvailable = updateAvailable;
}


QString Updater::downloadUrl() const
{
    return m_downloadUrl;
}

void Updater::setDownloadUrl(const QString &downloadUrl)
{
    m_downloadUrl = downloadUrl;
}


QString Updater::latestVersion() const
{
    return m_latestVersion;
}

void Updater::setLatestVersion(const QString &latestVersion)
{
    m_latestVersion = latestVersion;
}

bool Updater::compareVersion(const QString &x, const QString &y)
{
    QStringList versionsX = x.split(".");
    QStringList versionsY = y.split(".");

    int count = qMin(versionsX.count(), versionsY.count());

    for (int i = 0; i < count; ++i) {
        int a = QString(versionsX.at(i)).toInt();
        int b = QString(versionsY.at(i)).toInt();

        if (a > b) {
            return true;
        }

        else if (b > a) {
            return false;
        }
    }

    return versionsY.count() < versionsX.count();
}
