#include "downloadmanager.h"
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QCoreApplication>

DownloadManager::DownloadManager(QObject *parent) : QObject(parent)
{
    createNetworkAccessManager();
    m_startTime = 0;
}

void DownloadManager::createNetworkAccessManager()
{
    if (m_manager){
        m_manager->deleteLater();
    }
    m_manager = new QNetworkAccessManager(this);
}

void DownloadManager::doDownload(const QUrl &url)
{
    createNetworkAccessManager();
    QNetworkRequest request(url);
    m_reply = m_manager->get(request);
    m_startTime = QDateTime::currentDateTime().toTime_t();
    m_filePath = getSaveFilePath(url);
    qDebug() << "save file to:" << m_filePath;
    connect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadManager::updateProgress);
    connect(m_reply, &QNetworkReply::finished, this, &DownloadManager::onFinished);
    connect(m_reply, &QNetworkReply::redirected, this, &DownloadManager::doDownload);
}

void DownloadManager::onFinished()
{
    qDebug() << "onFinished";
    m_reply->close();
    m_reply->deleteLater();
    Q_EMIT finished(m_filePath);
}

QString DownloadManager::getSaveFilePath(const QUrl &url)
{
    QString basename = url.fileName();

    if (basename.isEmpty()) {
        basename = "download";
    }

    auto workDir = QTemporaryDir().path();
    QDir(workDir).mkpath(".");

    QString filePath = QString("%1/%2").arg(workDir).arg(basename);

    if (QFile::exists(filePath)) {
        // already exists, don't overwrite
        QFile::remove(filePath);
    }

    return filePath;
}

bool DownloadManager::isHttpRedirect(QNetworkReply *reply)
{
    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    return statusCode == 301 || statusCode == 302 || statusCode == 303
           || statusCode == 305 || statusCode == 307 || statusCode == 308;
}

void DownloadManager::saveFile(qint64 received, qint64 total)
{
    Q_UNUSED(received);
    Q_UNUSED(total);

    /* Check if we need to redirect */
    QUrl url = m_reply->attribute(
                   QNetworkRequest::RedirectionTargetAttribute).toUrl();
    if (!url.isEmpty()) {
        qDebug() << url;
        doDownload(url);
        return;
    }
    /* Save downloaded data to disk */

    QFile file(m_filePath);
    if (file.open(QIODevice::WriteOnly | QIODevice::Append)) {
        file.write(m_reply->readAll());
        file.close();
    }
}

void DownloadManager::calculateSizes(qint64 received, qint64 total)
{
    QString totalSize;
    QString receivedSize;

    if (total < 1024) {
        totalSize = tr("%1 bytes").arg(total);
    }

    else if (total < 1048576) {
        totalSize = tr("%1 KB").arg(round(total / 1024));
    }

    else {
        totalSize = tr("%1 MB").arg(round(total / 1048576));
    }

    if (received < 1024) {
        receivedSize = tr("%1 bytes").arg(received);
    }

    else if (received < 1048576) {
        receivedSize = tr("%1 KB").arg(received / 1024);
    }

    else {
        receivedSize = tr("%1 MB").arg(received / 1048576);
    }

    qDebug() << (tr("Downloading updates")
                 + " (" + receivedSize + " " + tr("of")
                 + " " + totalSize + ")");
}

void DownloadManager::updateProgress(qint64 received, qint64 total)
{
    if (total > 0) {
        qDebug() << "progress:" << QString("%1%").arg(QString::number(received * 100 / total));
//        calculateSizes (received, total);
//        calculateTimeRemaining (received, total);
        saveFile(received, total);
    } else {
        qDebug() << "download error";
    }
}

void DownloadManager::calculateTimeRemaining(qint64 received, qint64 total)
{
    uint difference = QDateTime::currentDateTime().toTime_t() - m_startTime;
    qDebug() << difference;
    if (difference > 0) {
        QString timeString;
        qreal timeRemaining = total / (received / difference);

        if (timeRemaining > 7200) {
            timeRemaining /= 3600;
            int hours = int (timeRemaining + 0.5);

            if (hours > 1) {
                timeString = tr("about %1 hours").arg(hours);
            } else {
                timeString = tr("about one hour");
            }
        }

        else if (timeRemaining > 60) {
            timeRemaining /= 60;
            int minutes = int (timeRemaining + 0.5);

            if (minutes > 1) {
                timeString = tr("%1 minutes").arg(minutes);
            } else {
                timeString = tr("1 minute");
            }
        }

        else if (timeRemaining <= 60) {
            int seconds = int (timeRemaining + 0.5);

            if (seconds > 1) {
                timeString = tr("%1 seconds").arg(seconds);
            } else {
                timeString = tr("1 second");
            }
        }

        qDebug() << (tr("Time remaining") + ": " + timeString);
    }
}
