//
// Created by 张雪明 <zhangxueming@uniontech.com> on 2024/9/25.
//

#include "ImmutableTask.h"
#include "utils/Utils.h"
#include "utils/Process.h"
#include <QJsonObject>
#include <QDateTime>
#include <QDebug>

ImmutableTask::ImmutableTask() : AsyncTask(),
    m_opType(OperateType::Invalid)
{}

ImmutableTask::ImmutableTask(OperateType opType) : AsyncTask(),
    m_opType(opType)
{
}

ImmutableTask::~ImmutableTask()
{
    this->stopTimer();
}

void ImmutableTask::init()
{
    m_progress = 0;
    m_remainSecond = 0;

    connect(&m_timer, &QTimer::timeout, this, &ImmutableTask::onTimeOut);
}

void ImmutableTask::onTimeOut()
{
    m_progress += 3;
    if (m_progress >= 98) {
        m_progress = 98;
    }
    this->estimateRemainTime();
    reportProgress(m_progress, m_remainSecond);
}

void ImmutableTask::estimateRemainTime()
{
    QTime currTime = QTime::currentTime();
    int elapsed = m_startTime.msecsTo(currTime);
    double speed = (m_progress * 1000.0) / elapsed;
    if (0 < speed) {
        m_remainSecond = (100 - m_progress) / speed;
    }
}

void ImmutableTask::readStandardOutput()
{

}

void ImmutableTask::readAllStandardError()
{
    AsyncTask::readAllStandardError();
}

bool ImmutableTask::buildArgumentsForBackup()
{
    return true;
}

bool ImmutableTask::buildArgumentsForRestore(const QString &)
{
    return true;
}

void ImmutableTask::setSnapshotID(const QString &id)
{
    m_snapshotID = id;
}

void ImmutableTask::setSnapshotName(const QString &name)
{
    m_snapshotName = name;
}

void ImmutableTask::setSnapshotDesc(const QString &desc)
{
    m_snapshotDes = desc;
}

void ImmutableTask::setUiOperateUserName(const QString &userName)
{
    m_uiOperateUserName = userName;
}

void ImmutableTask::doResult()
{
    switch (m_opType) {
        case OperateType::ImmutableSystemBackup: {
            this->creatSnapshot(m_snapshotName, m_snapshotDes);
            break;
        }
        case OperateType::ImmutableSystemRestore: {
            this->rollbackSnapshot(m_snapshotID);
            break;
        }
        default:
            break;
    }
}

bool ImmutableTask::creatSnapshot(const QString &name, const QString &des)
{
    m_progress = 1;
    QStringList args;
    args <<"snapshot"<<"create"<<"--json"<<"--"<<name<<des;
    QJsonObject jsonObject;
    QString out;
    QString err;
    if (!Process::spawnCmd(m_immutableCtlCmd, args, out, err)) {
        qCritical()<<"snapshot create failed, snapshotName: "<<name<<", err: "<<err<<", out: "<<out;
        if (err.isEmpty()) {
            if (!out.isEmpty()) {
                err = out;
            }
        }

        QJsonObject outObj = Utils::QStringToJson(out);
        QJsonObject outErrObj = outObj.value("error").toObject();

        Response rsp;
        rsp.progress = 0;
        rsp.remainSecond = 0;
        rsp.errMsg = err;
        rsp.errCodeStr = outErrObj.value("code").toString();

        Q_EMIT error(rsp.marshal());
        return false;
    }

    QJsonObject outObj = Utils::QStringToJson(out);
    outObj.insert("uiOperateUserName", m_uiOperateUserName);
    Q_EMIT success(outObj);
    return true;
}

bool ImmutableTask::rollbackSnapshot(const QString &id)
{
    m_progress = 1;
    QString snapshotID = id;
    qInfo()<<"rollbackSnapshot, snapshotID = "<<snapshotID;
    QStringList args;
    args <<"snapshot"<<"rollback"<<snapshotID<<"--json";
    QJsonObject jsonObject;
    QString out;
    QString err;
    if (!Process::spawnCmd(m_immutableCtlCmd, args, out, err)) {
        qCritical()<<"snapshot rollback failed, snapshotID: "<<snapshotID<<", err: "<<err<<", out: "<<out;
        if (err.isEmpty()) {
            if (!out.isEmpty()) {
                err = out;
            }
        }

        QJsonObject outObj = Utils::QStringToJson(out);
        QJsonObject outErrObj = outObj.value("error").toObject();

        Response rsp;
        rsp.progress = 0;
        rsp.remainSecond = 0;
        rsp.errMsg = err;
        rsp.errCodeStr = outErrObj.value("code").toString();

        Q_EMIT error(rsp.marshal());
        return false;
    }

    Q_EMIT success(QJsonObject());
    return true;
}

void ImmutableTask::startTimer()
{
    m_timer.setInterval(500);
    if (!m_timer.isActive()) {
        m_timer.start();
    }

    m_startTime = QTime::currentTime();
    m_progress = 0;
    m_remainSecond = 0;
}

void ImmutableTask::stopTimer()
{
    if (m_timer.isActive()) {
        m_timer.stop();
    }
}

void ImmutableTask::reportProgress(int progress, int remainSecond)
{
    QJsonObject jsonObject;
    jsonObject.insert("progress", progress);
    jsonObject.insert("remainSecond", remainSecond);
    Q_EMIT progressChanged(jsonObject);
}
