//
// Created by uos on 2022/3/16.
//

#include "RestoreModule.h"
#include "utils/Utils.h"
#include "utils/Process.h"
#include <QDateTime>
#include <QJsonValue>
#include <QJsonArray>
#include <QJsonObject>
#include <DDialog>
#include <QUuid>
#include "common/CommonFunc.h"

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

}

RestoreModule::~RestoreModule()
{

}

void RestoreModule::initialize()
{
    if (m_restoreWidget == nullptr) {
        m_restoreWidget = new RestoreWidget;
    }

    connect(m_restoreWidget, &RestoreWidget::notifySystemRestore, [=] {
        this->checkAdminAuthority(AuthorityType::SystemRestoreV20);
    });

    connect(m_restoreWidget, &RestoreWidget::notifyDataRestore, [=] {
        this->checkCommonAuthority(AuthorityType::DataRestore);
    });

    connect(m_restoreWidget, &RestoreWidget::notifyInitializeRestore, [=] {
        this->checkAdminAuthority(AuthorityType::InitRestoreV20);
    });
    connect(m_restoreWidget, &RestoreWidget::notifyOtherRestore, this, &RestoreModule::onOtherRestore);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportProgress,
            this, &RestoreModule::updateProgress);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Error,
            this, &RestoreModule::onError);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportSpace, this, &RestoreModule::onSpaceChanged);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Success,
            this, &RestoreModule::onSuccess);
}

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

QString RestoreModule::icons() const
{
    return QString(":/resources/icons/backup_module.png");
}

QString RestoreModule::text() const
{
    return QString(tr("Restore"));
}

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

void RestoreModule::setSelinuxEnable(bool enable)
{
    m_isSelinuxEnabled = enable;
}

void RestoreModule::setLVM(bool isLVM)
{
    m_isLVMOnly = isLVM;
}

void RestoreModule::setEncrypted(bool isEncrypted)
{
    m_isEncrypted = isEncrypted;
}

void RestoreModule::setFileMgrEncrypted(bool encrypt)
{
    m_isFileMgrEncrypted = encrypt;
}

void RestoreModule::setDevice(bool isDevice)
{
    m_isDevice = isDevice;
}

void RestoreModule::setSupportV20BackupRestore(bool isSupport)
{
    m_isSupportV20BackupRestore = isSupport;
}

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

void RestoreModule::doAdminAuthorityTask(bool result, int type)
{
    if (result) {
        AuthorityType authType = static_cast<AuthorityType>(type);
        if (AuthorityType::SystemRestoreV20 == authType) {
            return this->onSystemRestore();
        } else if (AuthorityType::InitRestoreV20 == authType) {
            return this->onInitializeRestore();
        }
    }
}

void RestoreModule::checkCommonAuthority(AuthorityType type)
{
    if (nullptr == m_commonAuthUtils) {
        m_commonAuthUtils = new AuthorityUtils();
        connect(m_commonAuthUtils, &AuthorityUtils::notifyCommonUserAuthority, this, &RestoreModule::doCommonAuthorityTask);
    }

    m_commonAuthUtils->checkCommonUserAuthentication(type);
}

void RestoreModule::doCommonAuthorityTask(bool result, int type)
{
    if (result) {
        AuthorityType authType = static_cast<AuthorityType>(type);
        if (AuthorityType::DataRestore == authType) {
            return this->onDataRestore();
        }
    }
}

void RestoreModule::setMajorVersion(int version)
{
    m_osMajorVer = version;
}

void RestoreModule::setMinorVersion(int version)
{
    m_osMinorVer = version;
}

void RestoreModule::onSystemRestore()
{
    if (m_osMajorVer == OS_VERSION_MAJOR_V23 || m_osMajorVer >= OS_VERSION_MAJOR_V25) {
        if (m_systemRestoreWidget == nullptr) {
            m_systemRestoreWidget = new SystemRestoreWidget();
            connect(m_systemRestoreWidget, &SystemRestoreWidget::cancel, this, &RestoreModule::onBack);
            connect(m_systemRestoreWidget, &SystemRestoreWidget::start, this,
                    &RestoreModule::onStartSystemRestore);
        }
        QString content;
#ifdef UI_TEST
    QString filename = TEST_DATA_DIR"system_backup_info.json";
    QFile file(filename);
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    content = file.readAll();
    file.close();
#else
        auto reply = m_recoveryInterface->ListSystemBackup();
        reply.waitForFinished();
        if (!reply.isValid()) {
            qCritical() << reply.error();
            return;
        }
        content = reply.value();
#endif
        QJsonObject backupInfo = Utils::QStringToJson(content);
        auto array = backupInfo.value("backup").toArray();
        BackupInfoList backupInfoList;
        for (int i = 0; i < array.size(); ++i) {
            BackupInfo info;
            QJsonObject object = array.at(i).toObject();
            info.unmarshal(object);
            if (info.recoveryType == static_cast<int>(RecoveryType::OSTree)) {
                info.username = tr("Administrator");
                if (info.submissionType == CommitType::SystemCommit) {
                    info.remark = tr("Automatical backup before system updates");
                } else if (info.submissionType == CommitType::InstallerCommit) {
                    info.remark = tr("Initial backup during system installation");
                }
            } else if (info.operateType == static_cast<int> (OperateType::ImmutableSystemBackup)) {
                if ((info.submissionType == CommitType::InstallerCommit) &&
                    (info.recoveryType == static_cast<int> (RecoveryType::ImmutableMode))) {
                    continue;
                }
            }
            backupInfoList.append(info);
        }
        m_systemRestoreWidget->setData(backupInfoList);
        m_frameProxy->setCurrentWidget(this, m_systemRestoreWidget);
        return;
    }

    // v20
    if (!m_isSupportV20BackupRestore || m_isDevice || m_isLVMOnly || m_isEncrypted || m_isFileMgrEncrypted) {
        QString tips;
        if (!m_isSupportV20BackupRestore || m_isDevice) {
            tips = tr("System restore is not supported in the current environment.");
        } else if (m_isFileMgrEncrypted) {
            tips = tr("The system contains encrypted partition, please decrypt it before using the backup and restore function.");
        } else {
            tips = tr("System contains encrypted partition or lvm format partition, system restore is not supported.");
        }
        QString btnText = tr("OK", "button");
        if (m_resultWidget == nullptr) {
            m_resultWidget = new ResultWidget(true, tips, "", btnText, true);
            connect(m_resultWidget, &ResultWidget::done, this, &RestoreModule::onBackHome);
        } else {
            m_resultWidget->set(true, tips, "", btnText, true);
        }

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

        return;
    }

    return this->showSysRestoreWidgetV20();
}

void RestoreModule::showSysRestoreWidgetV20()
{
    if (m_sysRestoreWidgetV20 == nullptr) {
        m_sysRestoreWidgetV20 = new SysRestoreWidgetV20();

        connect(m_sysRestoreWidgetV20, &SysRestoreWidgetV20::requestManualRestore,
                this, &RestoreModule::onManualRestoreV20);
        connect(m_sysRestoreWidgetV20, &SysRestoreWidgetV20::cancelRestore,
                this, &RestoreModule::onCancelRestoreV20);
    }

    if (m_isSelinuxEnabled) {
        QString securityMsg = tr("The system has enabled security management and the backup and restore function cannot be used. Please contact the administrator.");
        if (!Common::isSeUser()) {
            m_sysRestoreWidgetV20->setEnableInHighSysLevelMode(false);
            m_sysRestoreWidgetV20->setTipsLabelText(securityMsg);
            m_sysRestoreWidgetV20->setTipsVisible(true);
        } else {
            m_sysRestoreWidgetV20->setTipsVisible(false);
        }
    }

    m_sysRestoreWidgetV20->initDFileChooserEdit();

    m_frameProxy->setCurrentWidget(this, m_sysRestoreWidgetV20);
}

void RestoreModule::onManualRestoreV20(const QString &path)
{
    V20RestoreReq req;
    req.actionType = static_cast<int> (ActionType::ManualRestore);
    req.operateType = static_cast<int> (OperateType::ManualRestoreV20);
    req.backupDir = path;
    req.language = QLocale::system().name();
    req.formatData = false;
    req.userName = Utils::getUserName();
    m_curSysOpID = req.operateID;

    QString reqStr = Utils::JsonToQString(req.marshal());
    // qWarning()<<"RestoreModule::onManualRestoreV20, req = "<<reqStr.toLocal8Bit().data();

    auto reply = m_recoveryInterface->SystemRestoreV20(req);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curSysOpID.clear();
        qCritical() << "RestoreModule::onManualRestoreV20 dbus err: "<<reply.error();
        return;
    }

    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
    m_frameProxy->setWindowFuncClose(false);
}

void RestoreModule::onCancelRestoreV20()
{
    V20BackupReq req;
    req.actionType = static_cast<int> (ActionType::CancelRestore);
    req.operateType = static_cast<int> (OperateType::CancelRestoreV20);
    req.userName = Utils::getUserName();
    m_curSysOpID = req.operateID;
    //QString reqStr;// = Utils::JsonToQString(req.marshal());
    qWarning()<<"onCancelRestoreV20, operateID = "<<req.operateID<<", opType = "<<req.operateType;

    auto reply = m_recoveryInterface->CancelBackupOrRestore20(req);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curSysOpID.clear();
        qCritical() << "RestoreModule::onCancelRestoreV20 dbus err: "<<reply.error();
        return;
    }

    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
    m_frameProxy->setWindowFuncClose(false);
}

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

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

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

    switch (opTye) {
        case OperateType::ManualRestoreV20: {
            if (nullptr != m_sysRestoreWidgetV20) {
                m_sysRestoreWidgetV20->doSuccess();
            }
            break;
        }
        case OperateType::CancelRestoreV20: {
            if (nullptr != m_sysRestoreWidgetV20) {
                m_sysRestoreWidgetV20->cancelRestoreSuccess();
                m_sysRestoreWidgetV20->showHistoryBackup();
            }
            break;
        }
        case OperateType::InitRestoreV20: {
            if (nullptr != m_initRestoreWidgetV20) {
                m_initRestoreWidgetV20->doSuccess();
            }
            break;
        }
        case OperateType::CancelInitRestoreV20: {
            if (nullptr != m_initRestoreWidgetV20) {
                m_initRestoreWidgetV20->doCancelRestoreSuccess();
            }
            break;
        }
        case OperateType::ImmutableSystemRestore: {
            onShowResult(true, operateType);
            break;
        }
        default:
            break;
    }
}

void RestoreModule::onStartSystemRestore(BackupInfo &backupInfo)
{
    DDialog dialog;
    dialog.setTitle(tr("Restore"));
    dialog.setMessage(tr("Your current system will be restored, and your data may be affected. Are you sure you want to restore your system?"));
    dialog.setIcon(QIcon::fromTheme("uos-recovery"));
    dialog.addButton(tr("Cancel", "button"));
    // QRect rect = geometry();
    // dialog.move(rect.center());
    dialog.moveToCenter();

    int result = dialog.addButton(tr("Restore", "button"), true, DDialog::ButtonWarning);
    if (dialog.exec() != result) {
        return;
    }

    m_frameProxy->setMenuDisabled(true);
    m_frameProxy->setQuitMenuDisabled(true);
    m_frameProxy->setWindowFuncClose(false);
    m_systemRestoreWidget->setTips(tr("Preparing for system restore..."));
    // m_systemRestoreWidget->setTipsStyleSheet("QLabel {"
    //                                             "color: #000000;"
    //                                             "}");
    m_systemRestoreWidget->startSpinner();

    SystemRestoreRequest request;
    request.username = Utils::getUserName();
    request.operateID = QUuid::createUuid().toString();
    request.backupInfo = backupInfo;
    m_curSysOpID = request.operateID;
    auto requestObject = request.marshal();
    QString reqStr = Utils::JsonToQString(requestObject);
    // qInfo()<<"system restore req: "<<reqStr.toLocal8Bit().data();
    auto reply = m_recoveryInterface->SystemRestore(request);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curSysOpID.clear();
        m_frameProxy->setMenuDisabled(false);
        m_frameProxy->setQuitMenuDisabled(false);
        m_frameProxy->setWindowFuncClose(true);
        m_systemRestoreWidget->setTips(tr("DBus error, please try again"));
        m_systemRestoreWidget->stopSpinner();
        qCritical() << reply.error();
        return;
    }

    if (backupInfo.recoveryType != static_cast<int>(RecoveryType::OSTree)) { // OSTree 是异步去处理的
        m_frameProxy->setMenuDisabled(false);
        m_frameProxy->setQuitMenuDisabled(false);
        m_frameProxy->setWindowFuncClose(true);
        m_systemRestoreWidget->setTips("");
        m_systemRestoreWidget->stopSpinner();
        if ((m_osMajorVer >= OS_VERSION_MAJOR_V25) && Utils::isImmutableSystem()) {
            onShowProgress(tr("Restoring..."),
                           tr("Time remaining:") + " ",
                           tr("To avoid data loss, please do not use your computer during the process."));
        } else {
            this->reboot();
        }
    }
}

int RestoreModule::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 RestoreModule::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 RestoreModule::onDataRestore()
{
    if (m_isSelinuxEnabled && Common::isSecurityEnhanced()) {
        QString securityMsg = tr("The system has enabled security management and the backup and restore function cannot be used. Please contact the administrator.");
        QString btnText = tr("OK", "button");
        if (m_resultWidget == nullptr) {
            m_resultWidget = new ResultWidget(true, securityMsg, "", btnText, true);
            connect(m_resultWidget, &ResultWidget::done, this, &RestoreModule::onBackHome);
        } else {
            m_resultWidget->set(true, securityMsg, "", btnText, true);
        }

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

    if (m_userDataRestoreWidget == nullptr) {
        m_userDataRestoreWidget = new UserDataRestoreWidget();
        connect(m_userDataRestoreWidget, &UserDataRestoreWidget::cancel, this, &RestoreModule::onBack);
        connect(m_userDataRestoreWidget, &UserDataRestoreWidget::start, this,
                &RestoreModule::onStartUserDataRestore);
    }

    if (nullptr == m_defaultDataRestoreWidget) {
        m_defaultDataRestoreWidget = new DefaultDataRestoreWidget();
        connect(m_defaultDataRestoreWidget, &DefaultDataRestoreWidget::cancel, this, &RestoreModule::onBack);
    }

    m_userDataRestoreWidget->setTips("");

    QString content;
    BackupInfoList backupInfoList;
    auto reply = m_recoveryInterface->ListUserDataBackup(Utils::getUserName());
    reply.waitForFinished();
    if (!reply.isValid()) {
        qCritical() << reply.error();
        return;
    }

    content = reply.value();
    QJsonObject backupInfo = Utils::QStringToJson(content);
    auto array = backupInfo.value("backup").toArray();
    int arraySize = array.size();
    for (int i = 0; i < arraySize; ++i) {
        BackupInfo info;
        QJsonObject object = array.at(i).toObject();
        info.unmarshal(object);
        if (OperateStatus::Success != info.status) {
            continue;
        }
        backupInfoList.append(info);
    }

    if (arraySize <= 0) {
        m_frameProxy->setCurrentWidget(this, m_defaultDataRestoreWidget);
        return;
    }

    m_userDataRestoreWidget->setData(backupInfoList);
    m_frameProxy->setCurrentWidget(this, m_userDataRestoreWidget);
}

void RestoreModule::onStartUserDataRestore(BackupInfo &backupInfo)
{
    if (m_recoveryInterface->IsRunning()) {
        QString operateID;
        QString userName;
        int opType;
        int progress;
        m_recoveryInterface->GetContext(operateID, userName, opType, progress);
        QString opTypeDes = Common::GetOperateTypeDes(opType);
        QString tips = tr("Task conflict, user %1's task %2 has not been completed").arg(userName).arg(opTypeDes);
        m_userDataRestoreWidget->setTips(tips);
        m_userDataRestoreWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        qWarning()<<"onStartUserDataRestore, another task is running, operateID = "<<operateID
                  <<", opType = "<<opType<<", progress = "<<progress;
        return;
    }

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

    UserDataRestoreRequest request;
    request.username = Utils::getUserName();
    request.operateID = QUuid::createUuid().toString();
    request.backupInfo = backupInfo;
    m_curUserOpID = request.operateID;
    // 调整一下结构中的rootUUID
    if (request.backupInfo.rootUUID.compare(m_frameProxy->rootUUID())) {
        request.backupInfo.rootUUID = m_frameProxy->rootUUID();
    }
   // auto requestObject = request.marshal();
    auto reply = m_recoveryInterface->UserDataRestore(request);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curUserOpID.clear();
        qCritical() << reply.error();
        onShowResult(false, static_cast<int>(OperateType::UserDataRestore), tr("DBus error, please try again"));
        return;
    }

    if (reply.value() != ErrorCode::OK) {
        m_curUserOpID.clear();
        qCritical() <<"data restore error: "<<reply.value();
        onShowResult(false, static_cast<int>(OperateType::UserDataRestore));
        return;
    }

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

void RestoreModule::onDimFileRestore(const QString &dimFilePath)
{
    if (m_restoreWidget->isVisible()) {
        m_restoreWidget->startCalculateTip(true, tr("Preparing for system restore..."));
    } else if (m_dimFileRestoreWidget->isVisible()) {
        m_dimFileRestoreWidget->startCalculateTip(true, tr("Preparing for system restore..."));
    }

    // 检测当前选中的目录是否满足dim文件解压要求，否则在全部设备中寻找空间满足要求的位置，如果没找到，提示用户空间不够不能进行还原
//    auto getPathReply = m_recoveryInterface->CheckDimFileSpace(dimFilePath);
//    getPathReply.waitForFinished();
//    if (!getPathReply.isValid()) {
//        onShowResult(false, static_cast<int>(OperateType::DimFileRestore), tr("DBus error, please try again"));
//    }

    m_frameProxy->setMenuDisabled(true);
    m_frameProxy->setQuitMenuDisabled(true);
    m_frameProxy->setWindowFuncClose(false);
    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
}

void RestoreModule::onInitializeRestoreV20()
{
    if (!m_isSupportV20BackupRestore || m_isFileMgrEncrypted) {
        QString tips = tr("System restore is not supported in the current environment.");
        if (m_isSupportV20BackupRestore) {
            if (m_isFileMgrEncrypted) {
                tips = tr("The system contains encrypted partition, please decrypt it before using the backup and restore function.");
            } else {
                tips.clear();
            }
        }
        QString btnText = tr("OK", "button");
        if (m_resultWidget == nullptr) {
            m_resultWidget = new ResultWidget(true, tips, "", btnText, true);
            connect(m_resultWidget, &ResultWidget::done, this, &RestoreModule::onBackHome);
        } else {
            m_resultWidget->set(true, tips, "", btnText, true);
        }

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

    if (m_initRestoreWidgetV20 == nullptr) {
        m_initRestoreWidgetV20 = new InitializeRestoreDim();

        connect(m_initRestoreWidgetV20, &InitializeRestoreDim::initializeRestoreV20Clicked,
                this, &RestoreModule::doInitializeRestoreV20);
        connect(m_initRestoreWidgetV20, &InitializeRestoreDim::cancelInitRestore,
                this, &RestoreModule::onCancelInitRestoreV20);
    }

    if (m_isSelinuxEnabled) {
        QString securityMsg = tr("The system has enabled security management and the backup and restore function cannot be used. Please contact the administrator.");
        if (Common::isSeUser()) {
            m_initRestoreWidgetV20->setEnableInSelinuxMode(true);
            m_initRestoreWidgetV20->setTipsVisible(false);
        } else {
            m_initRestoreWidgetV20->setEnableInSelinuxMode(false);
            m_initRestoreWidgetV20->setTipsLabelText(securityMsg);
            m_initRestoreWidgetV20->setTipsVisible(true);
        }
    }

    m_frameProxy->setCurrentWidget(this, m_initRestoreWidgetV20);
}

void RestoreModule::onInitializeRestore()
{
    if (m_osMajorVer >= OS_VERSION_MAJOR_V23) {
        DDialog dialog;
        dialog.setTitle(tr("Reset to factory settings"));
        dialog.setMessage(tr("It will restore data on your system disk, clear your username and password, but keep your personal data, please confirm before proceeding."));
        dialog.setIcon(QIcon::fromTheme("uos-recovery"));
        dialog.addButton(tr("Cancel", "button"));
        // QRect rect = geometry();
        // dialog.move(rect.center());
        dialog.moveToCenter();

        int result = dialog.addButton(tr("Confirm and Reset"), true, DDialog::ButtonWarning);
        if (dialog.exec() != result) {
            return;
        }

        //const int OSMajorVerionV23 = 23;
        int osVersion = 0;
        QSettings versionFile("/etc/os-version", QSettings::IniFormat);
        versionFile.beginGroup("Version");
        osVersion = versionFile.value("MajorVersion").toInt();
        versionFile.endGroup();

        if (osVersion == 20) {
            // 到/recovery/backup目录下寻找v20的初始化备份文件
            auto hasInitBack = m_recoveryInterface->HasInitBackDimFile();
            hasInitBack.waitForFinished();
            if (!hasInitBack.isValid()) {
                onShowResult(false, static_cast<int>(OperateType::DimFileRestore), tr("DBus error, please try again"));
                return;
            }

            if (hasInitBack.value()) {
                // 执行备份文件转换，还原系统
                onDimFileRestore("/recovery/backup");
                return;
            } else {
                // 显示不存在初始化备份文件提示
                m_restoreWidget->setErrorInfo(tr("Cannot find the initial backup file"));
                return;
            }
        } else if (m_osMajorVer >= OS_VERSION_MAJOR_V23) {
            if (Utils::isOStree()) {
                m_restoreWidget->startCalculateTip(true, "");
                SystemRestoreRequest factoryRestoreReq;
                factoryRestoreReq.username = Utils::getUserName();
                factoryRestoreReq.operateID = QUuid::createUuid().toString();
                m_recoveryInterface->OStreeFactoryRestore(factoryRestoreReq);
            } else if (m_systemSyncType == static_cast<int> (RecoveryType::Rsync)) {
                m_restoreWidget->setErrorInfo(tr("Cannot find the initial backup file"));
                return;
            } else if (Utils::isImmutableSystem()) {
                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();
                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)) {
                            break;
                        }
                    }
                }

                if (intSnapshot.operateID.isEmpty()) {
                    m_restoreWidget->setErrorInfo(tr("Cannot find the initial backup file"));
                    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);
                // qInfo()<<"factory restore req: "<<reqStr.toLocal8Bit().data();
                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->setErrorInfo(tr("DBus error, please try again"));
                    qCritical() << restoreReply.error();
                    return;
                }

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

    if (m_osMajorVer < OS_VERSION_MAJOR_V23) {
        return this->onInitializeRestoreV20();
    }
}

void RestoreModule::doInitializeRestoreV20(bool formatData)
{
    V20RestoreReq req;
    req.actionType = static_cast<int> (ActionType::SystemRestore);
    req.operateType = static_cast<int> (OperateType::InitRestoreV20);
    req.language = QLocale::system().name();
    req.userName = Utils::getUserName();
    req.formatData = formatData;
    m_curSysOpID = req.operateID;

    QString reqStr = Utils::JsonToQString(req.marshal());
    // qWarning()<<"RestoreModule::doInitializeRestoreV20, req = "<<reqStr.toLocal8Bit().data();

    auto reply = m_recoveryInterface->SystemRestoreV20(req);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curSysOpID.clear();
        qCritical() << "RestoreModule::doInitializeRestoreV20 dbus err: "<<reply.error();
        return;
    }

    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
    m_frameProxy->setWindowFuncClose(false);
}

void RestoreModule::onCancelInitRestoreV20()
{
    V20BackupReq req;
    req.actionType = static_cast<int> (ActionType::CancelRestore);
    req.operateType = static_cast<int> (OperateType::CancelInitRestoreV20);
    req.userName = Utils::getUserName();
    m_curSysOpID = req.operateID;
    //QString reqStr;// = Utils::JsonToQString(req.marshal());
    qWarning()<<"onCancelInitRestoreV20, opID = "<<req.operateID<<", opType = "<<req.operateType;

    auto reply = m_recoveryInterface->CancelBackupOrRestore20(req);
    reply.waitForFinished();
    if (!reply.isValid()) {
        m_curSysOpID.clear();
        qCritical() << "RestoreModule::onCancelInitRestoreV20 dbus err: "<<reply.error();
        return;
    }

    m_frameProxy->enableBackWard(false);
    m_frameProxy->enableModule(false);
    m_frameProxy->setWindowFuncClose(false);
}

void RestoreModule::restoreToOStreeFactory(const QString &request)
{
    int errCode = -1; //m_recoveryInterface->OStreeFactoryRestore(request);
    if (static_cast<int> (ErrorCode::OK) != errCode) {
        QString errorMsg = tr("Cannot find the initial backup file");
        DDialog dialog;
        dialog.setTitle(tr("Reset to factory settings"));
        dialog.setMessage(errorMsg);
        dialog.setIcon(QIcon::fromTheme("uos-recovery"));
        dialog.addButton(tr("OK", "button"), true);
        // QRect rect = geometry();
        // dialog.move(rect.center());
        dialog.moveToCenter();
        dialog.exec();
    }
}

void RestoreModule::onOtherRestore()
{
    static QString osEditionType = Utils::getOSEditionType();
    if ("Community" == osEditionType) {
        DDialog dlg;
        dlg.setMessage(tr("It is unavailable for deepin alpha version"));
        dlg.setIcon(QIcon::fromTheme("dialog-warning"));
        // QRect rect = geometry();
        // dlg.move(rect.center());
        dlg.moveToCenter();
        dlg.exec();
        return;
    }

    if (!Utils::authorization()) {
        return;
    }

    if (m_dimFileRestoreWidget == nullptr) {
        m_dimFileRestoreWidget = new dimFileRestoreWidget();
        connect(m_dimFileRestoreWidget, &dimFileRestoreWidget::cancelBtnSignal, this, &RestoreModule::onBack);
        connect(m_dimFileRestoreWidget, &dimFileRestoreWidget::startDimRestoreSignal, this, &RestoreModule::onDimFileRestore);
    }

    m_dimFileRestoreWidget->setErrorTips("");
    m_frameProxy->setCurrentWidget(this, m_dimFileRestoreWidget);
}

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

void RestoreModule::onBackHome()
{
    if (m_isDimFileRestoreDone) {
        m_isDimFileRestoreDone = false;
        // 显示提示重启的弹窗
        if (showRebootDialog(tr("Restore"),
                             tr("System restore is ready. Do you want to reboot and restore your system now?"),
                             "uos-recovery", tr("Cancel", "button"), tr("Reboot and Restore"))) {
            // 重启系统
            auto rebootReply = m_recoveryInterface->Reboot();
            rebootReply.waitForFinished();
            if (!rebootReply.isValid()) {
                onShowResult(false, static_cast<int>(OperateType::DimFileRestore), tr("DBus error, please try again"));
                return;
            }
        } else {
            // 还原根分区下的配置文件
//            auto reply = m_recoveryInterface->ClearDimFileRestoreCfg(m_dimRestoreImgFilePath);
//            reply.waitForFinished();
//            if (!reply.isValid()) {
//                onShowResult(false, static_cast<int>(OperateType::DimFileRestore), tr("DBus error, please try again"));
//                return;
//            }
//
//            if (reply.value() != OK) {
//                return;
//            }
        }
    }

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

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

    if (operateType == static_cast<int>(OperateType::UserDataRestore) ||
        operateType == static_cast<int>(OperateType::SystemRestore) ||
        operateType == static_cast<int>(OperateType::ImmutableSystemRestore)) {
        resultText = success ? tr("Restore successful!") : tr("Sorry, restore failed!");
    } else if (operateType == static_cast<int>(OperateType::DimFileRestore)) {
        resultText = success ? tr("The backup file was parsed successfully") : tr("Failed to parse the backup file");
        m_isDimFileRestoreDone = success;
    } 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 ResultWidget(success, resultText, errorMsg, btnText, false);
        connect(m_resultWidget, &ResultWidget::done, this, &RestoreModule::onBackHome);
    } else {
        m_resultWidget->set(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)) {
        this->reboot();
    }
}

void RestoreModule::onShowProgress(const QString &mainTitle, const QString &subTitle, const QString &warning)
{
    if (m_progressWidget == nullptr) {
        m_progressWidget = new ProgressWidget(mainTitle, subTitle, warning);
    } else {
        m_progressWidget->setMainTitle(mainTitle);
        m_progressWidget->setSubTitle(subTitle);
        m_progressWidget->setWarning(warning);
    }
    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);
    m_progressWidget->start();
}

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

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

    auto curProgress = jsonObject.value("progress").toInt();
    if (operateType == static_cast<int>(OperateType::SystemRestore)) {
        if (curProgress >= 100) {
            if (jsonObject.contains("OStreeOperate")) {
                m_frameProxy->setMenuDisabled(false);
                m_frameProxy->setQuitMenuDisabled(false);
                m_frameProxy->setWindowFuncClose(true);
                if (nullptr != m_systemRestoreWidget) {
                    m_systemRestoreWidget->setTips("");
                    m_systemRestoreWidget->stopSpinner();
                }

                static const int OSTREE_ROLLBACK = 2;
                static const int OSTREE_SUCESS = 0;
                int opType = jsonObject.value("OStreeOperate").toInt();
                int state = -1;
                if (jsonObject.contains("OStreeState")) {
                    state = jsonObject.value("OStreeState").toInt();
                }

                if ((opType == OSTREE_ROLLBACK) && (state == OSTREE_SUCESS)) {
                    // OSTree 环境下需要在接收到 StateChanged成功的信号之后重启系统
                    m_restoreWidget->startCalculateTip(false, "");
                    this->reboot();
                }
                return;
            }
        }
    }

    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 RestoreModule::onError(const QString &errMsg)
{
    QJsonObject jsonObject = Utils::QStringToJson(errMsg);
    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");
            }
            DDialog dialog;
            dialog.setTitle(tr("Reset to factory settings"));
            dialog.setMessage(errorMsg);
            dialog.setIcon(QIcon::fromTheme("uos-recovery"));
            dialog.addButton(tr("OK", "button"), true);
            // QRect rect = geometry();
            // dialog.move(rect.center());
            dialog.moveToCenter();
            dialog.exec();
        }

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

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

        if (operateType == OperateType::SystemRestoreV20 || operateType == OperateType::ManualRestoreV20 ||
            operateType == OperateType::CancelRestoreV20) {
            if (nullptr != m_sysRestoreWidgetV20) {
                m_sysRestoreWidgetV20->doError(rsp.retCode);
            }
        } else if (operateType == OperateType::InitRestoreV20 || operateType == OperateType::CancelInitRestoreV20) {
            if (nullptr != m_initRestoreWidgetV20) {
                m_initRestoreWidgetV20->doError(rsp.retCode);
            }
        }

        m_frameProxy->enableBackWard(true);
        m_frameProxy->enableModule(true);
        m_frameProxy->setWindowFuncClose(true);
        return;
    } else if (operateType == OperateType::UserDataRestore) {
        if (m_curUserOpID == curOperateID) {
            onShowResult(false, opType, errInfo);
        }
        return;
    }

    if (m_curSysOpID != curOperateID) {
        return;
    }
    onShowResult(false, opType, errInfo);
}

void RestoreModule::onSpaceChanged(const QString &space)
{
    QJsonObject jsonObject = Utils::QStringToJson(space);
    int operateType = jsonObject.value("operateType").toInt();
    if (operateType == static_cast<int>(OperateType::CheckDimFileUseSpace)) {
        // 处理提示
        QString dimFilePath = jsonObject.value("dimFilePath").toString();
        m_dimRestoreImgFilePath = jsonObject.value("imgFilePath").toString();
        if (m_dimRestoreImgFilePath.isEmpty()) {
            // 显示空间不够不能还原提示
            if (m_restoreWidget->isVisible()) {
                m_restoreWidget->startCalculateTip(false, tr("Unable to perform the system restore: insufficient disk space"));
            } else if (m_dimFileRestoreWidget->isVisible()) {
                m_dimFileRestoreWidget->startCalculateTip(false, tr("Unable to perform the system restore: insufficient disk space"));
            }

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

        } else {
            // 显示空间不够不能还原提示
            if (m_restoreWidget->isVisible()) {
                m_restoreWidget->startCalculateTip(false, "");
            } else if (m_dimFileRestoreWidget->isVisible()) {
                m_dimFileRestoreWidget->startCalculateTip(false, "");
            }

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

//            auto reply = m_recoveryInterface->DimFileToLoopDeviceFile(dimFilePath, m_dimRestoreImgFilePath);
//            reply.waitForFinished();
//            if (!reply.isValid()) {
//                qCritical() << reply.error();
//                onShowResult(false, static_cast<int>(OperateType::DimFileRestore), tr("DBus error, please try again"));
//                return;
//            }
        }
    }
}

void RestoreModule::setSystemSyncType(int type)
{
    m_systemSyncType = type;
}

void RestoreModule::setUserDataSyncType(int type)
{
    m_userDataSyncType = type;
}
