//
// Created by 张雪明 <zhangxueming@uniontech.com> on 2024/11/19.
//
#include "ImmuFactoryRestoreModule.h"
#include "utils/Utils.h"
#include <DDialog>

ImmuFactoryRestoreModule::ImmuFactoryRestoreModule(FrameProxyInterface *frame, ComDeepinDaemonUosrecoveryInterface *interface,
        QObject *parent)
        : QObject(parent)
        , ModuleInterface(frame, interface)
{}

ImmuFactoryRestoreModule::~ImmuFactoryRestoreModule()
{}

void ImmuFactoryRestoreModule::initialize()
{
    if (m_restoreWidget == nullptr) {
        m_restoreWidget = new ImmuFactoryRestoreWidget;
    }

    QSize iconSize(149,149);
    QString initRestoreIconPath = ":/resources/icons/v25/initialize_restore_v25.png";
    m_initRestoreIcon = Utils::hidpiPixmap(initRestoreIconPath, iconSize);

    connect(m_restoreWidget, &ImmuFactoryRestoreWidget::immuFactoryRestoreClicked,
            this, &ImmuFactoryRestoreModule::onImmuFactoryRestore);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportProgress,
            this, &ImmuFactoryRestoreModule::updateProgress);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Error,
            this, &ImmuFactoryRestoreModule::onError);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Success,
            this, &ImmuFactoryRestoreModule::onSuccess);
}

QString ImmuFactoryRestoreModule::name() const
{
    return "ImmuFactoryRestoreModule";
}

QString ImmuFactoryRestoreModule::icons() const
{
    return QString(":/resources/icons/v25/init_selected.svg");
}

QString ImmuFactoryRestoreModule::text() const
{
    return QString(tr("Reset to factory settings"));
}

void ImmuFactoryRestoreModule::active()
{
    m_frameProxy->popAllWidget();
    m_frameProxy->setCurrentWidget(this, m_restoreWidget);
}

void ImmuFactoryRestoreModule::onImmuFactoryRestore()
{
    this->checkAdminAuthority(AuthorityType::ImmuFactoryRestore);
}

void ImmuFactoryRestoreModule::factoryRestore()
{
    int retCode = m_restoreWidget->showFactoryRestoreTips();
    if (0 != retCode) {
        m_restoreWidget->setRestartBtnVisible(true);
        return;
    }

    auto reply = m_recoveryInterface->ListSystemBackup();
    reply.waitForFinished();
    if (!reply.isValid()) {
        qCritical() << reply.error();
        return;
    }
    QString content = reply.value();
    QJsonObject backupInfo = Utils::QStringToJson(content);
    auto array = backupInfo.value("backup").toArray();
    bool findInitSnapshot = false;
    BackupInfo intSnapshot;
    for (int i = 0; i < array.size(); ++i) {
        QJsonObject object = array.at(i).toObject();
        intSnapshot.unmarshal(object);
        if (intSnapshot.operateType == static_cast<int> (OperateType::ImmutableSystemBackup)) {
            if ((intSnapshot.submissionType == CommitType::InstallerCommit)) {
                findInitSnapshot = true;
                break;
            }
        }
    }

    if (!findInitSnapshot || intSnapshot.operateID.isEmpty()) {
        m_restoreWidget->setTipsLabelText(tr("Cannot find the initial backup file"));
        m_restoreWidget->setTipsVisible(true);
        m_restoreWidget->setRestartBtnVisible(true);
        return;
    }

    m_frameProxy->setMenuDisabled(true);
    m_frameProxy->setQuitMenuDisabled(true);
    m_frameProxy->setWindowFuncClose(false);

    SystemRestoreRequest request;
    request.username = Utils::getUserName();
    request.operateID = QUuid::createUuid().toString();
    request.backupInfo = intSnapshot;
    m_curSysOpID = request.operateID;
    auto requestObject = request.marshal();
    QString reqStr = Utils::JsonToQString(requestObject);
    auto restoreReply = m_recoveryInterface->SystemRestore(request);
    restoreReply.waitForFinished();
    m_frameProxy->setMenuDisabled(false);
    m_frameProxy->setQuitMenuDisabled(false);
    m_frameProxy->setWindowFuncClose(true);
    if (!restoreReply.isValid()) {
        m_curSysOpID.clear();
        m_restoreWidget->setTipsLabelText(tr("DBus error, please try again"));
        m_restoreWidget->setRestartBtnVisible(true);
        qCritical() << restoreReply.error();
        return;
    }

    onShowProgress(tr("Restoring..."),
                   tr("Time remaining:") + " ",
                   tr("To avoid data loss, please do not use your computer during the process."));
}

void ImmuFactoryRestoreModule::onBack()
{
    if (m_frameProxy) {
        m_frameProxy->back();
    }
}

void ImmuFactoryRestoreModule::onBackHome()
{
    if (nullptr != m_frameProxy) {
        m_frameProxy->backHome();
    }
}

void ImmuFactoryRestoreModule::onShowResult(bool success, int operateType, const QString &errorMsg)
{
    QString resultText = "";
    QString btnText = tr("OK", "button");

    if (operateType == static_cast<int>(OperateType::ImmutableSystemRestore)) {
        resultText = success ? tr("Restore successful!") : tr("Sorry, restore failed!");
    } else {
        return ;
    }

    m_frameProxy->setMenuDisabled(false);
    m_frameProxy->setQuitMenuDisabled(false);
    m_frameProxy->setWindowFuncClose(true);

    if (m_progressWidget != nullptr) {
        m_frameProxy->popWidget();
    }

    if (m_resultWidget == nullptr) {
        m_resultWidget = new ResultWidgetV2(operateType, success, resultText, errorMsg, btnText, false);
        connect(m_resultWidget, &ResultWidgetV2::done, this, &ImmuFactoryRestoreModule::onBackHome);
    } else {
        m_resultWidget->set(operateType, success, resultText, errorMsg, btnText, false);
    }

    m_frameProxy->setCurrentWidget(this, m_resultWidget);
    m_frameProxy->enableBackWard(true);
    m_frameProxy->enableModule(true);

    if (operateType == static_cast<int>(OperateType::ImmutableSystemRestore)) {
        if (success) {
            this->reboot();
        }
    }
}

void ImmuFactoryRestoreModule::onShowResult(bool success, const Response &rsp)
{
    if (rsp.operateType != OperateType::ImmutableSystemRestore) {
        return;
    }

    int operateType = static_cast<int>(rsp.operateType);
    QString err = tr("Operation failed,error code: %1").arg(rsp.errCodeStr);
    QString resultText = success ? tr("Restore successful!") : tr("Sorry, restore failed!");
    if ( !success) {
        resultText = err;
    }

    QString btnText = tr("OK", "button");

    m_frameProxy->setMenuDisabled(false);
    m_frameProxy->setQuitMenuDisabled(false);
    m_frameProxy->setWindowFuncClose(true);

    if (m_progressWidget != nullptr) {
        m_frameProxy->popWidget();
    }

    if (m_resultWidget == nullptr) {
        m_resultWidget = new ResultWidgetV2(operateType, success, resultText, rsp.errMsg, btnText, false);
        connect(m_resultWidget, &ResultWidgetV2::done, this, &ImmuFactoryRestoreModule::onBackHome);
    } else {
        m_resultWidget->set(operateType, success, resultText, rsp.errMsg, btnText, false);
    }

    m_frameProxy->setCurrentWidget(this, m_resultWidget);
    m_frameProxy->enableBackWard(true);
    m_frameProxy->enableModule(true);

    if (success) {
        this->reboot();
    }
}

void ImmuFactoryRestoreModule::onShowProgress(const QString &mainTitle, const QString &subTitle, const QString &warning)
{
    if (m_progressWidget == nullptr) {
        m_progressWidget = new ProgressWidgetV2(mainTitle, subTitle, warning);
    } else {
        m_progressWidget->setMainTitle(mainTitle);
        m_progressWidget->setSubTitle(subTitle);
        m_progressWidget->setWarning(warning);
    }
    m_progressWidget->setIconPixmap(m_initRestoreIcon);
    m_progressWidget->setValue(0);
    m_frameProxy->setCurrentWidget(this, m_progressWidget);
    m_frameProxy->setMenuDisabled(true);
    m_frameProxy->setQuitMenuDisabled(true);
    m_frameProxy->setWindowFuncClose(false);
    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
}

void ImmuFactoryRestoreModule::updateProgress(const QString &progress)
{
    QJsonObject jsonObject = Utils::QStringToJson(progress);
    int operateType = jsonObject.value("operateType").toInt();
    if (operateType != static_cast<int>(OperateType::ImmutableSystemRestore)) {
        return;
    }

    QString curOperateID = jsonObject.value("operateID").toString();
    if ((operateType == static_cast<int>(OperateType::ImmutableSystemRestore)) && curOperateID != m_curSysOpID) {
        return;
    }

    auto curProgress = jsonObject.value("progress").toInt();
    if (m_progressWidget != nullptr) {
        auto remainSecond = jsonObject.value("remainSecond").toInt();
        m_progressWidget->setRemainTime(remainSecond);
        m_progressWidget->setValue(curProgress);
        if (curProgress >= 100) {
            onShowResult(true, operateType);
        }
    }
}

void ImmuFactoryRestoreModule::onError(const QString &errMsg)
{
    QJsonObject jsonObject = Utils::QStringToJson(errMsg);
    Response rsp;
    rsp.unmarshal(jsonObject);
    QString errInfo = "Unknown";
    if (jsonObject.contains("errMsg")) {
        errInfo = jsonObject.value("errMsg").toString();
    }

    int opType = -1;
    if (jsonObject.contains("operateType")) {
        opType = jsonObject.value("operateType").toInt();
    }
    QString curOperateID = jsonObject.value("operateID").toString();

    if (static_cast<int> (OperateType::FactoryRestore) == opType) {
        Response rsp;
        rsp.unmarshal(jsonObject);

        QString errorMsg = tr("DBus error, please try again");
        if (static_cast<int> (ErrorCode::OK) != rsp.retCode) {
            if (static_cast<int> (ErrorCode::NoInitBackup) == rsp.retCode) {
                errorMsg = tr("Cannot find the initial backup file");
            } else if (static_cast<int> (ErrorCode::OSTreeRunning) == rsp.retCode) {
                errorMsg = tr("OSTree is Running, please wait");
            }
        }

        if (nullptr != m_restoreWidget) {
        //    m_restoreWidget->startCalculateTip(false, "");
        }
        return;
    }

    OperateType operateType = static_cast<OperateType>(opType);
    if (operateType == OperateType::InitRestoreV20) {
        V20Response rsp;
        rsp.unmarshal(jsonObject);
        if (m_curSysOpID != rsp.operateID) {
            return;
        }

        m_frameProxy->enableBackWard(true);
        m_frameProxy->enableModule(true);
        m_frameProxy->setWindowFuncClose(true);
        return;
    }

    if (m_curSysOpID != curOperateID) {
        return;
    }

    if (operateType == OperateType::ImmutableSystemRestore) {
        onShowResult(false, rsp);
    } else {
        onShowResult(false, opType, errInfo);
    }
}

void ImmuFactoryRestoreModule::onSuccess(const QString &msg)
{
    QJsonObject jsonObject = Utils::QStringToJson(msg);
    int operateType = jsonObject.value("operateType").toInt(-1);
    OperateType opTye = static_cast<OperateType>(operateType);
    if (!(OperateType::ImmutableSystemRestore == opTye)) {
        return;
    }

    V20Response rsp;
    rsp.unmarshal(jsonObject);
    if (m_curSysOpID != rsp.operateID) {
        return;
    }

    qWarning()<<"ImmuFactoryRestoreModule::onSuccess, msg: "<<msg.toLocal8Bit().data();
    m_frameProxy->enableBackWard(true);
    m_frameProxy->enableModule(true);
    m_frameProxy->setWindowFuncClose(true);

    switch (opTye) {
        case OperateType::ImmutableSystemRestore: {
            onShowResult(true, operateType);
            break;
        }
        default:
            break;
    }
}

void ImmuFactoryRestoreModule::doAdminAuthorityTask(bool result, int type)
{
    if (result) {
        AuthorityType authType = static_cast<AuthorityType>(type);
        if (AuthorityType::ImmuFactoryRestore == authType) {
            return this->factoryRestore();
        }
    }
}

int ImmuFactoryRestoreModule::reboot()
{
    if (showRebootDialog(tr("Restore"),
                         tr("System restore is ready. Do you want to reboot and restore your system now?"),
                         "uos-recovery", tr("Reboot Later"), tr("Reboot and Restore"))) {
        auto rebootReply = m_recoveryInterface->Reboot();
        rebootReply.waitForFinished();
        if (!rebootReply.isValid()) {
            qCritical() << Q_FUNC_INFO <<" call Reboot failed! " << rebootReply.error();
            return -1;
        }
    }

    return 0;
}

bool ImmuFactoryRestoreModule::showRebootDialog(const QString &title, const QString &msg, const QString &iconName,
                      const QString &leftBtnText, const QString &rightBtnText)
{
    DDialog dialog;
    dialog.setTitle(title);
    dialog.setMessage(msg);
    dialog.setIcon(QIcon::fromTheme(iconName));
    dialog.addButton(leftBtnText);
    // QRect rect = geometry();
    // dialog.move(rect.center());
    dialog.moveToCenter();

    int result = dialog.addButton(rightBtnText, true, DDialog::ButtonWarning);
    if (dialog.exec() != result) {
        return false;
    }

    return true;
}

void ImmuFactoryRestoreModule::checkAdminAuthority(AuthorityType type)
{
    if (nullptr == m_adminAuthUtils) {
        m_adminAuthUtils = new AuthorityUtils();
        connect(m_adminAuthUtils, &AuthorityUtils::notifyAdminAuthority, this, &ImmuFactoryRestoreModule::doAdminAuthorityTask);
    }
    m_adminAuthUtils->authorization(type);
}
