#include "downloadworker.h"

#include <QProcess>
#include <QRegularExpression>
#include <QtConcurrent>
#include <QStandardPaths>

#define DEFAULTURL "d.store.deepinos.org.cn"
#define MAXWAITTIME 200000

DownloadController::DownloadController(QObject *parent)
{
    Q_UNUSED(parent)

    // 初始化默认域名
    domains.clear();
    domains.append(DEFAULTURL);

    /*
    domains = {
        "d1.store.deepinos.org.cn",
        "d2.store.deepinos.org.cn",
        "d3.store.deepinos.org.cn",
        "d4.store.deepinos.org.cn",
        "d5.store.deepinos.org.cn"
    };
    */
    this->threadNum = domains.size();
}

void DownloadController::setFilename(QString filename)
{
    this->filename = filename;
}

bool checkMeatlink(QString metaUrl)
{
    QFile metaStatus("/tmp/spark-store/metaStatus.txt");
    if (metaStatus.exists())
    {
        metaStatus.remove();
    }
    QString cmd = QString("curl -I -s --connect-timeout 5 %1 -w  %{http_code}  |tail -n1 > /tmp/spark-store/metaStatus.txt").arg(metaUrl);
    system(cmd.toUtf8().data());
    if (metaStatus.open(QFile::ReadOnly) && QString(metaStatus.readAll()).toUtf8() == "200")
    {
        metaStatus.remove();
        return true;
    }
    return false;
}

void gennerateDomain(QVector<QString> &domains)
{
    QFile serverList(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/server.list");
    if (serverList.open(QFile::ReadOnly))
    {
        QStringList list = QString(serverList.readAll()).trimmed().split("\n");
        qDebug() << list << list.size();
        domains.clear();

        for (int i = 0; i < list.size(); i++)
        {
            if (list.at(i).contains("镜像源 Download only") && i + 1 < list.size())
            {
                for (int j = i + 1; j < list.size(); j++)
                {
                    domains.append(list.at(j));
                }
                break;
            }
        }
        if (domains.size() == 0)
        {
            domains.append(DEFAULTURL);
        }
    }
    else
    {
        domains.append(DEFAULTURL);
    }
}

/**
 * @brief 开始下载
 */
void DownloadController::startDownload(const QString &url)
{
    // 获取下载任务信息
    fileSize = getFileSize(url);
    if (fileSize == 0)
    {
        emit errorOccur("文件大小获取失败");
        return;
    }

    QtConcurrent::run([=]()
    {
        QString metaUrl = url + ".metalink";
        qDebug() << "metalink" << metaUrl;
        bool useMetalink = false;
        if (checkMeatlink(metaUrl))
        {
            useMetalink = true;
            qDebug() << "useMetalink:" << useMetalink;
        }
        else
        {
            gennerateDomain(domains);
            // qDebug() << domains << domains.size();
        }

        QString aria2Command = "-d"; //下载目录
        QString aria2Urls = ""; //下载地址
        QString aria2Verbose = "--summary-interval=1"; //显示下载速度
        QString aria2SizePerThreads = "--min-split-size=1M"; //最小分片大小
        QString aria2NoConfig = "--no-conf"; //不使用配置文件
        QString aria2NoSeeds = "--seed-time=0"; //不做种
        QStringList command;
        QString downloadDir = "/tmp/spark-store/"; //下载目录
        QString aria2ConnectionPerServer = "--max-connection-per-server=1"; //每个服务器最大连接数
        QString aria2ConnectionMax = "--max-concurrent-downloads=16"; //最大同时下载数
        QString aria2ConnectionTimeout = "--connect-timeout=5"; // 5 秒服务器连接超时
        QString aria2MaxRetry = "--max-tries=1"; //设置最大重试次数


        if (useMetalink) //如果是metalink
        {
            command.append(metaUrl.toUtf8());
        }
        else
        {
            for (int i = 0; i < domains.size(); i++) //遍历域名
            {
                command.append(replaceDomain(url, domains.at(i)).replace("+","%2B").toUtf8()); //对+进行转译，避免oss出错
            }
        }


        qint64 downloadSizeRecord = 0; //下载大小记录
        qint8  failDownloadTimes = 0; // 记录重试次数
        const qint8 maxRetryTimes = 3; //最大重试次数
        QString speedInfo = ""; //显示下载速度
        QString percentInfo = ""; //显示下载进度
        command.append(aria2Command.toUtf8());
        command.append(downloadDir.toUtf8());
        command.append(aria2Verbose.toUtf8());
        command.append(aria2NoConfig.toUtf8());
        command.append(aria2SizePerThreads.toUtf8());
        command.append(aria2ConnectionPerServer.toUtf8());
        command.append(aria2ConnectionMax.toUtf8());
        command.append(aria2ConnectionTimeout.toUtf8());
        command.append(aria2MaxRetry.toUtf8());

        if (useMetalink)
        {
            command.append(aria2NoSeeds.toUtf8());
        }
        qDebug() << command;

        bool downloadSuccess = true;
        QProcess cmd;
        cmd.setProcessChannelMode(QProcess::MergedChannels);
        cmd.setProgram("aria2c");
        cmd.setArguments(command);
        cmd.start();
        cmd.waitForStarted(-1); //等待启动完成

        // Timer
        QTimer *timeoutTimer = new QTimer(this);
        timeoutTimer->setSingleShot(true); // 单次触发
        connect(timeoutTimer, &QTimer::timeout, [&]() {
            if (failDownloadTimes < maxRetryTimes) {
                qDebug() << "Download timeout, restarting...";
                // 重新启动下载任务的代码
                restartDownload(cmd, command); // 调用重新启动下载任务的函数
                failDownloadTimes += 1;
                timeoutTimer->start(MAXWAITTIME); // 重新启动定时器
            } else{
                emit errorOccur(tr("Download Failed, please retry :(")); // 下载失败
                downloadSuccess = false;
                cmd.close();
                cmd.terminate(); // 终止当前的下载进程
                cmd.waitForFinished(); // 等待进程结束
            }
        });

        connect(&cmd, &QProcess::readyReadStandardOutput, [&]()
        {
            timeoutTimer->start(MAXWAITTIME); // 重置超时计时器，15秒超时
            //通过读取输出计算下载速度
            QString message = cmd.readAllStandardOutput().data();
            message = message.replace(" ", "");
            QStringList list;
            qint64 downloadSize = 0;
            int downloadSizePlace1 = message.indexOf("(");
            int downloadSizePlace2 = message.indexOf(")");
            int speedPlace1 = message.indexOf("DL:");
            int speedPlace2 = message.indexOf("ETA");
            if (downloadSizePlace1 != -1 && downloadSizePlace2 != -1)
            {
                percentInfo = message.mid(downloadSizePlace1 + 1, downloadSizePlace2 - downloadSizePlace1 - 1).replace("%", "");
                if (percentInfo != "s")
                {
                    int percentInfoNumber = percentInfo.toUInt();

                    downloadSize = percentInfoNumber * fileSize / 100;
                }
            }
            if (speedPlace1 != -1 && speedPlace2 != -1 && speedPlace2 - speedPlace1 <= 15)
            {
                speedInfo = message.mid(speedPlace1 + 3, speedPlace2 - speedPlace1 - 3);
                speedInfo += "/s";
            }
            if (downloadSize >= downloadSizeRecord)
            {
                downloadSizeRecord = downloadSize;
                timeoutTimer->stop(); // 如果有进度，停止超时计时器
            }
            if (percentInfo == "OK")
            {
                finished = true;
                emit downloadProcess("", fileSize, fileSize);
                qDebug() << "finished:" << finished;
            }
            else
            {
                emit downloadProcess(speedInfo, downloadSizeRecord, fileSize);
            }
        });
        connect(&cmd, &QProcess::readyReadStandardError, [&]()
        {
            emit errorOccur(cmd.readAllStandardError().data());
            downloadSuccess = false;
            cmd.close();
        });

        pidNumber = cmd.processId();

        cmd.waitForFinished(-1);
        cmd.close();

        if(!downloadSuccess)
        {
            return;
        }

        // 统计下载量
        QString SenderdPath = "/opt/durapps/spark-store/bin/ss-feedback/sender-d";
        /*
        * https://en.wikipedia.org/wiki/HD_70642
        * HD 70642 is a star with an exoplanetary companion in the southern constellation of Puppis. 
        */
        QProcess mailProcess;
        mailProcess.start(SenderdPath.toUtf8(), QStringList() << metaUrl << "HD70642");
        mailProcess.waitForStarted();
        mailProcess.waitForFinished(3000);
        mailProcess.close();

        emit downloadFinished(); });
}

/**
 * @brief 停止下载
 */
void DownloadController::stopDownload()
{
    if (pidNumber < 0)
    {
        return;
    }

    // 实现下载进程退出
    QString killCmd = QString("kill -9 %1").arg(pidNumber);
    system(killCmd.toUtf8());
    qDebug() << "kill aria2!";
    pidNumber = -1;
}

void DownloadController::restartDownload(QProcess &cmd, const QStringList &command)
{
    cmd.terminate(); // 终止当前的下载进程
    cmd.waitForFinished(); // 等待进程结束
    cmd.setArguments(command); // 重新设置参数
    cmd.start(); // 重新启动下载
    cmd.waitForStarted(-1); // 等待启动完成
}

qint64 DownloadController::getFileSize(const QString &url)
{
    // 已经无需使用 qtnetwork 再获取 filesize，完全交给 aria2 来计算进度。 为保证兼容性，故保留此函数。
    qDebug() << "Begin download:" << url;
    qint64 fileSize = 10000;
    return fileSize;
}

QString DownloadController::replaceDomain(const QString &url, const QString domain)
{
    QRegularExpression regex(R"((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9])");
    if (regex.match(url).hasMatch())
    {
        return QString(url).replace(regex.match(url).captured(), domain);
    }
    return url;
}
