
#include "BackupModule.h"
#include "utils/Utils.h"
#include "utils/global.h"
#include "utils/Device.h"
#include "common/CommonFunc.h"
#include <QString>
#include <QObject>
#include <QFile>



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

}

BackupModule::~BackupModule()
{

}

void BackupModule::initialize()
{
    if (m_backupWidget == nullptr) {
        m_backupWidget = new BackupWidget();
    }

    connect(m_backupWidget, &BackupWidget::notifySystemBackup, [=] {
        this->checkAdminAuthority(AuthorityType::SystemBackupV20);
    });
    connect(m_backupWidget, &BackupWidget::notifyDataBackup, [=] {
        this->checkCommonAuthority(AuthorityType::DataBackup);
    });
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportProgress,
            this, &BackupModule::updateProgress);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Error,
            this, &BackupModule::onError);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportSpace,
            this, &BackupModule::onSpaceChanged);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::ReportCheckSpace,
            this, &BackupModule::onReportCheckSpace);
    connect(m_recoveryInterface, &ComDeepinDaemonUosrecoveryInterface::Success,
            this, &BackupModule::onSuccess);

#ifdef UI_TEST
    m_timer = new QTimer(this);
    m_timer->setInterval(100);
    connect(m_timer, &QTimer::timeout, this, &BackupModule::onTimeout);
#endif
}

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

void BackupModule::active()
{
    m_frameProxy->popAllWidget();
    m_frameProxy->setCurrentWidget(this, m_backupWidget);
}

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

QString BackupModule::text() const
{
    return QString(tr("Backup"));
}

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

    m_adminAuthUtils->authorization(type);
}

void BackupModule::doAdminAuthorityTask(bool result, int type)
{
    if (result) {
        AuthorityType authType = static_cast<AuthorityType>(type);
        if (AuthorityType::SystemBackupV20 == authType) {
            return this->onSystemBackup();
        }
    }
}

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

    m_commonAuthUtils->checkCommonUserAuthentication(type);
}

void BackupModule::doCommonAuthorityTask(bool result, int type)
{
    if (result) {
        AuthorityType authType = static_cast<AuthorityType>(type);
        if (AuthorityType::DataBackup == authType) {
            qWarning()<<"Authority end, show DataBackup";
            return this->onDataBackup();
        }
    }
}

void BackupModule::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->enableBackWard(false);
    m_frameProxy->enableModule(false);
    m_progressWidget->start();
}

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

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

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

void BackupModule::onShowResult(bool success, int operateType, const QString &errorMsg)
{
    if (operateType != static_cast<int>(OperateType::SystemBackup) &&
        operateType != static_cast<int>(OperateType::ImmutableSystemBackup) &&
        operateType != static_cast<int>(OperateType::UserDataBackup)) {
        return;
    }

    QString resultText = success ? tr("Backup successful!") : tr("Sorry, backup failed!");
    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 ResultWidget(success, resultText, errorMsg, btnText, false);
        connect(m_resultWidget, &ResultWidget::done, this, &BackupModule::onBackHome);
    } else {
        m_resultWidget->set(success, resultText, errorMsg, btnText, false);
    }

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

void BackupModule::onSystemBackup()
{
    if (m_osMajorVer == OS_VERSION_MAJOR_V23 || m_osMajorVer >= OS_VERSION_MAJOR_V25) {
        if (m_systemBackupWidget == nullptr) {
            m_systemBackupWidget = new SystemBackupWidget();
            if (m_systemSyncType == static_cast<int>(RecoveryType::OSTree) ||
                m_systemSyncType == static_cast<int>(RecoveryType::ImmutableMode)) {
                m_systemBackupWidget->setDestBtnEnabled(false);
            }

            connect(m_systemBackupWidget, &SystemBackupWidget::cancel, this, &BackupModule::onBack);
            connect(m_systemBackupWidget, &SystemBackupWidget::start, this,
                    &BackupModule::onStartSystemBackup);
            connect(m_systemBackupWidget, &SystemBackupWidget::notifySetDestPartition, [=] {
                m_frameProxy->showSettingDialog();
            });
            connect(m_systemBackupWidget, &SystemBackupWidget::notifyBackupManage, [=] {
                m_frameProxy->showBackupFileManagerDialog();
            });
        }

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

        auto destUUIDReply = m_recoveryInterface->GetBackupDeviceUUID(m_frameProxy->rootUUID());
        destUUIDReply.waitForFinished();
        if (!destUUIDReply.isValid()) {
            qCritical() << destUUIDReply.error();
       //     onShowResult(false, static_cast<int>(OperateType::SystemBackup),
        //                 tr("DBus error, please try again"));
      //      return;
        }

        m_destUUID = destUUIDReply.value();
        if (!m_destUUID.isEmpty()) {
            //    qInfo() << "destUUID=" << m_destUUID;
            auto partitionReply = m_recoveryInterface->GetPartition(m_destUUID);
            partitionReply.waitForFinished();
            if (!partitionReply.isValid()) {
                qCritical() << "GetPartition failed, err: "<<partitionReply.error();
           //     return;
            }
            QString partitionInfo = partitionReply.value();
            m_systemBackupWidget->setDestPartitionText(Utils::QStringToJson(partitionInfo));
        }
        m_systemBackupWidget->setNotes("");

        m_frameProxy->setCurrentWidget(this, m_systemBackupWidget);
        return;
    }

    // v20
    if (!m_isSupportV20BackupRestore || m_isDevice || m_isLVMOnly || m_isEncrypted || m_isFileMgrEncrypted) {
        QString tips;
        if (!m_isSupportV20BackupRestore || m_isDevice) {
            tips = tr("System backup 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 backup 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, &BackupModule::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->showSysBackupWidgetV20();
}

void BackupModule::showSysBackupWidgetV20()
{
    if (m_sysBackWidgetV20 == nullptr) {
        m_sysBackWidgetV20 = new SysBackupWidgetV20();

        connect(m_sysBackWidgetV20, &SysBackupWidgetV20::requestSetManualBackupDirectory,
                this, &BackupModule::onManualBackupV20);
        connect(m_sysBackWidgetV20, &SysBackupWidgetV20::requestSetSystemBackupDirectory,
                this, &BackupModule::onSystemBackupV20);
        connect(m_sysBackWidgetV20, &SysBackupWidgetV20::cancelBackup,
                this, &BackupModule::onCancelBackupV20);
        connect(m_sysBackWidgetV20, &SysBackupWidgetV20::requestReboot,
                this, &BackupModule::onRequestRebootV20);
    }

    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_sysBackWidgetV20->setEnableInHighSysLevelMode(false);
            m_sysBackWidgetV20->setTipsLabelText(securityMsg);
            m_sysBackWidgetV20->setTipsVisible(true);
        } else {
            m_sysBackWidgetV20->setTipsVisible(false);
        }
    }

    m_frameProxy->setCurrentWidget(this, m_sysBackWidgetV20);
}

void BackupModule::onManualBackupV20(const QString &path)
{
    m_backupPath = "";
    V20BackupReq req;
    req.actionType = static_cast<int> (ActionType::ManualBackup);
    req.operateType = static_cast<int> (OperateType::ManualBackupV20);
    req.backupPath = path;
    req.language = QLocale::system().name();
    req.userName = Utils::getUserName();
    m_curSysOpID = req.operateID;
    QString reqStr = Utils::JsonToQString(req.marshal());
    // qWarning()<<"BackupModule::onManualBackupV20, req = "<<reqStr.toLocal8Bit().data();

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

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

void BackupModule::onSystemBackupV20(const QString &path)
{
    m_backupPath = path;
    V20BackupReq req;
    req.actionType = static_cast<int> (ActionType::SystemBackup);
    req.operateType = static_cast<int> (OperateType::SystemBackupV20);
    req.backupPath = path;
    req.language = QLocale::system().name();
    req.userName = Utils::getUserName();
    m_curSysOpID = req.operateID;
    QString reqStr = Utils::JsonToQString(req.marshal());
    // qWarning()<<"BackupModule::onSystemBackupV20, req = "<<reqStr.toLocal8Bit().data();

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

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

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

    QString curOperateID = jsonObject.value("operateID").toString();
    if (m_curSysOpID != curOperateID) {
        return;
    }
    // qWarning()<<"BackupModule::onSuccess, msg: "<<msg.toLocal8Bit().data();

    if (nullptr != m_sysBackWidgetV20) {
        if (opTye == OperateType::SystemBackupV20 || opTye == OperateType::ManualBackupV20) {
            m_sysBackWidgetV20->doSuccess();
        } else if (opTye == OperateType::CancelBackupV20) {
            m_sysBackWidgetV20->cancelBackupSuccess();
        }
    }

    if (opTye == OperateType::ImmutableSystemBackup) {
        onShowResult(true, static_cast<int>(OperateType::ImmutableSystemBackup), "");
    }

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

void BackupModule::onRequestRebootV20()
{
    if (m_backupPath.endsWith("#")) {
        V20BackupReq req;
        req.actionType = static_cast<int> (ActionType::SystemBackup);
        req.operateType = static_cast<int> (OperateType::RemoveCoverBackupV20);
        req.backupPath = m_backupPath.left(m_backupPath.length() - 1);
        req.language = QLocale::system().name();
        req.userName = Utils::getUserName();
        m_curSysOpID = req.operateID;
        QString reqStr = Utils::JsonToQString(req.marshal());
        // qWarning()<<"req: "<<reqStr.toLocal8Bit().data();
        auto reply = m_recoveryInterface->Remove(req);
        reply.waitForFinished();
        if (!reply.isValid()) {
            m_curSysOpID.clear();
            qCritical() << "BackupModule::onSystemBackupV20 dbus err: "<<reply.error();
            return;
        }
    }

    Utils::reboot(true, false);
}

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

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

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

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

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

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

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

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

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

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

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

void BackupModule::setSystemBackupSpaceTips(const QString &tips)
{
    if (m_systemBackupWidget != nullptr) {
        m_systemBackupWidget->setTips(tips);
    }
}

void BackupModule::onStartSystemBackup(const QString &remark)
{
    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);
        // if (progress > 0) {
        //     tips = tr("another task(%1: %2%) is running, User: %3").arg(opTypeDes).arg(progress).arg(userName);
        // } else {
        //     tips = tr("another task(%1) is running, User: %2").arg(opTypeDes).arg(progress).arg(userName);
        // }
        m_systemBackupWidget->setTips(tips);
        m_systemBackupWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        // qWarning()<<"onStartSystemBackup, another task is running, operateID = "<<operateID<<", userName = "<<userName
        //     <<", opType = "<<opType<<", progress = "<<progress;
        return;
    }

    m_curSysBackupReq.clear();
    m_frameProxy->setMenuDisabled(true);
    m_frameProxy->setQuitMenuDisabled(true);
    m_frameProxy->setWindowFuncClose(false);

    SystemBackupRequest request;
    request.userName = Utils::getUserName();
    request.rootUUID = m_frameProxy->rootUUID();
    request.destUUID = m_destUUID;
    request.remark = remark;
    request.operateID = QUuid::createUuid().toString();
    request.snapshotName = Utils::getOSVersion();
    m_curSysOpID = request.operateID;
    QJsonObject jsonObject = request.marshal();

    m_systemBackupWidget->setTips("");
    if (Utils::isImmutableSystem()) {
        auto reply = m_recoveryInterface->SystemBackup(request);
        reply.waitForFinished();
        if (!reply.isValid()) {
            m_curSysOpID.clear();
            qCritical() << Q_FUNC_INFO << " SystemBackup isvalid!";
            onShowResult(false, static_cast<int>(OperateType::ImmutableSystemBackup),
                         tr("DBus error, please try again"));
            return;
        }

        int replayValue = reply.value();
        if (replayValue != ErrorCode::OK) {
            qInfo()<<"SystemBackup replayValue = "<<replayValue;
            // TODO: 可以根据具体的错误码显示更详细的错误提示信息，先简单显示
            onShowResult(false, static_cast<int>(OperateType::ImmutableSystemBackup),
                         tr("Sorry, backup failed!"));
            return;
        }

        onShowProgress(tr("Backing up..."),
                       tr("Time remaining:") + " ",
                       tr("To avoid data loss, please do not use your computer during the process."));
        return;
    } else {
        auto checkSpaceReply = m_recoveryInterface->CheckIncSystemBackupSpace(request.destUUID);
        checkSpaceReply.waitForFinished();
        if (!checkSpaceReply.isValid()) {
            m_curSysOpID.clear();
            qCritical() << Q_FUNC_INFO << " checkSpaceReply isvalid!";
            onShowResult(false, static_cast<int>(OperateType::SystemBackup),
                         tr("DBus error, please try again"));
            return;
        }
    }

    m_curSysBackupReq = Utils::JsonToQString(jsonObject);
    m_curSystemBackupRequest = request;
}

void BackupModule::onDataBackup()
{
    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, &BackupModule::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_dataBackupWidget == nullptr) {
        m_dataBackupWidget = new DataBackupWidget();
        connect(m_dataBackupWidget, &DataBackupWidget::cancel, this, &BackupModule::onBack);
        connect(m_dataBackupWidget, &DataBackupWidget::start,
                this, &BackupModule::onDataBackupCheckSpace);
    } else {
        m_dataBackupWidget->resetWidget();
    }

    qWarning()<<"onDataBackup, ListPartition";
    auto partitionReply = m_recoveryInterface->ListPartition(true);
    partitionReply.waitForFinished();
    if (!partitionReply.isValid()) {
        qCritical() << "ListPartition err, "<< partitionReply.error();
        onShowResult(false, static_cast<int>(OperateType::UserDataBackup),
                     tr("DBus error, please try again"));
        return;
    }

    m_dataBackupWidget->setDestDevice(Utils::QStringToJson(partitionReply.value()));
    m_frameProxy->setCurrentWidget(this, m_dataBackupWidget);
    qWarning()<<"onDataBackup, m_curUserOpID: "<<m_curUserOpID;

#if 0
    if (m_userDataBackupSelectWidget == nullptr) {
        m_userDataBackupSelectWidget = new UserDataBackupSelectWidget();
        connect(m_userDataBackupSelectWidget, &UserDataBackupSelectWidget::cancel, this, &BackupModule::onBack);
        connect(m_userDataBackupSelectWidget, &UserDataBackupSelectWidget::next,
                this, &BackupModule::onCheckSpace);
    }

    m_userDataBackupSelectWidget->setTips("");

    //获取家目录文件
    QString userPath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
    QDir userDir(userPath);
    m_fileItems.clear();
    auto fileInfoList = userDir.entryInfoList(QDir::Files | QDir::Hidden | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Type| QDir::DirsFirst);
    for (auto &fileInfo : fileInfoList) {
        FileItem fileItem;
        fileItem.fileName = fileInfo.fileName();
        fileItem.size = fileInfo.size();
        qInfo() << fileInfo.absoluteFilePath();
        if (fileInfo.isDir()) {
            fileItem.fileType = FileType::Dir;
            QDir subDir(fileInfo.absoluteFilePath());
            auto subFileInfoList = subDir.entryInfoList(QDir::Files | QDir::Hidden | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Type| QDir::DirsFirst);
            for (auto &subFileInfo : subFileInfoList) {
                qInfo() << subFileInfo.absoluteFilePath();
                FileItem childFileItem;
                childFileItem.fileName = subFileInfo.fileName();
                childFileItem.size = subFileInfo.size();
                if (subFileInfo.isDir()) {
                    childFileItem.fileType = FileType::Dir;
                } else {
                    childFileItem.fileType = FileType::File;
                }
                fileItem.children.append(childFileItem);
            }
        } else {
            fileItem.fileType = FileType::File;
        }
        m_fileItems.append(fileItem);
    }
    m_userDataBackupSelectWidget->setFiles(m_fileItems);

    auto partitionReply = m_recoveryInterface->ListPartition(true);
    partitionReply.waitForFinished();
    if (!partitionReply.isValid()) {
        qCritical() << partitionReply.error();
        onShowResult(false, static_cast<int>(OperateType::UserDataBackup),
                     tr("DBus error, please try again"));
        return;
    }

    m_userDataBackupSelectWidget->setDestDevice(Utils::QStringToJson(partitionReply.value()));
    m_frameProxy->setCurrentWidget(this, m_userDataBackupSelectWidget);
#endif
}

QStringList BackupModule::getUsrDataSpecialExcludes()
{
    QStringList excludes = {
            ".config/browser/Default/virtual"
    };

    return excludes;
}

void BackupModule::onStartDataBackup(const QString &remark)
{
    if (m_userDataBackupWidget == nullptr) {
        qCritical() << "m_userDataBackupWidget is nullptr";
        return;
    }

    UserDataBackupRequest request;
    request.username = Utils::getUserName();
    request.remark = remark;
    request.destUUID = m_destUUID;
    request.operateID = QUuid::createUuid().toString();
    m_curUserOpID = request.operateID;
    if (!m_destUUID.isEmpty()) {
        m_frameProxy->setMenuDisabled(true);
        m_frameProxy->setQuitMenuDisabled(true);
        m_frameProxy->setWindowFuncClose(false);

        request.rootUUID = m_frameProxy->rootUUID();
        request.exclude = m_excludes;
    //    QJsonObject jsonObject = request.marshal();
        auto requestReply = m_recoveryInterface->UserDataBackup(request);
        requestReply.waitForFinished();
        if (!requestReply.isValid()) {
            m_curUserOpID.clear();
            qCritical() << requestReply.error();
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup), tr("DBus error, please try again"));
            return;
        }
        if (requestReply.value() != OK) {
            m_curUserOpID.clear();
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup));
            return;
        }
        onShowProgress(tr("Backing up..."),
                       tr("Time remaining:") + " ",
                       tr("To avoid data loss, please do not use your computer during the process."));
    }
}

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

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

void BackupModule::updateDestPartition(const QJsonObject &jsonObject)
{
    if (m_systemBackupWidget != nullptr) {
        m_systemBackupWidget->setDestPartitionText(jsonObject);
    }

    if (jsonObject.contains("uuid")) {
        m_destUUID = jsonObject.value("uuid").toString();
    }
}

#ifdef UI_TEST
void BackupModule::onTimeout()
{
    m_progressWidget->setValue(++m_progress);
    if (m_progress > 50) {
        m_timer->stop();
        m_progress = 0;
        onShowResult(false, SystemBackup, "test");
    }
}


#endif

void BackupModule::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(-1);
    }
    QString curOperateID = jsonObject.value("operateID").toString();

    OperateType operateType = static_cast<OperateType>(opType);
    if (operateType == OperateType::SystemBackupV20 || operateType == OperateType::ManualBackupV20 ||
        operateType == OperateType::CancelBackupV20) {
        m_frameProxy->enableBackWard(true);
        m_frameProxy->enableModule(true);
        m_frameProxy->setWindowFuncClose(true);
        // qCritical()<<"BackupModule::onError, errMsg = "<<errMsg.toLocal8Bit().data();

        V20Response rsp;
        rsp.unmarshal(jsonObject);
        if (nullptr != m_sysBackWidgetV20) {
            if (operateType == OperateType::SystemBackupV20 || operateType == OperateType::ManualBackupV20) {
                if (m_curSysOpID == curOperateID) {
                    m_sysBackWidgetV20->doError(rsp.retCode);
                    m_curSysOpID.clear();
                }
            }
        }
    } else {
        if ((operateType == OperateType::CheckUserDataBackupSpace && m_curUserOpID != curOperateID) ||
            (operateType == OperateType::UserDataBackup && m_curUserOpID != curOperateID)) {
            return;
        }
        // qCritical()<<"BackupModule::onError, errMsg = "<<errMsg.toLocal8Bit().data();
        m_curUserOpID.clear();
        onShowResult(false, opType, errInfo);
    }
}

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

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

void BackupModule::doDataBackup()
{
    if (nullptr == m_dataBackupWidget) {
        qCritical() << "doDataBackup, m_dataBackupWidget is nullptr";
        return;
    }

    UserDataBackupRequest request;
    request.username = Utils::getUserName();
    request.remark = m_dataBackupWidget->getNote();
    request.destUUID = m_destUUID;
    request.operateID = QUuid::createUuid().toString();
    m_curUserOpID = request.operateID;
    if (!m_destUUID.isEmpty()) {
        m_frameProxy->setMenuDisabled(true);
        m_frameProxy->setQuitMenuDisabled(true);
        m_frameProxy->setWindowFuncClose(false);

        request.rootUUID = m_frameProxy->rootUUID();
        request.exclude = m_excludes;
        request.filesFrom = m_dataBackupWidget->getBackupFiles();
     //   QJsonObject jsonObject = request.marshal();
     //   QString request = Utils::JsonToQString(jsonObject);
    //    qWarning()<<"doDataBackup, request = "<<request.toLocal8Bit().data();
        auto requestReply = m_recoveryInterface->UserDataBackup(request);
        requestReply.waitForFinished();
        if (!requestReply.isValid()) {
            qCritical() << requestReply.error();
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup), tr("DBus error, please try again"));
            return;
        }
        if (requestReply.value() != OK) {
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup));
            return;
        }
        onShowProgress(tr("Backing up..."),
                       tr("Time remaining:") + " ",
                       tr("To avoid data loss, please do not use your computer during the process."));
    }
}

void BackupModule::onSpaceChanged(const QString &space)
{
    QJsonObject jsonObject = Utils::QStringToJson(space);
    int operateType = jsonObject.value("operateType").toInt();
    QString curOperateID = jsonObject.value("operateID").toString();
    if (curOperateID != m_curUserOpID) {
        return;
    }
    // qWarning()<<"onSpaceChanged, space: "<<space.toLocal8Bit().data();

    if (operateType == static_cast<int>(OperateType::CheckUserDataBackupSpace)) {
        m_frameProxy->setMenuDisabled(false);
        m_frameProxy->setQuitMenuDisabled(false);
        m_frameProxy->setWindowFuncClose(true);
        bool hasSpace = false;
        if (jsonObject.contains("hasSpace")) {
            hasSpace = jsonObject.value("hasSpace").toBool();
        }

        if (!hasSpace) {
            if (nullptr != m_dataBackupWidget) {
                m_dataBackupWidget->setButtonEnable(true);
                m_dataBackupWidget->stopSpinner();
                m_dataBackupWidget->setTips(tr("Insufficient disk space on the device"));
                m_dataBackupWidget->setTipsStyleSheet("QLabel {"
                                                      "color: #FF5736;"
                                                      "}");
            }
            return;
        }

        return this->doDataBackup();
    }
}

void BackupModule::onDataBackupCheckSpace(const QString &msg)
{
    // m_dataBackupWidget->setTips(tr(""));
    QStringList backupFiles = m_dataBackupWidget->getBackupFiles();
    QStringList denyFileList; // = Common::getDenyUserSecurityList("uos-recovery");
    QString bindPath;
    for (QString &denyPath : denyFileList) {
        if (denyPath.startsWith("/home/")) {
            bindPath = m_dataBackupWidget->getDirBindPath("/home");
            int index = bindPath.indexOf("/home");
            bindPath = bindPath.left(index);
        } else {
            bindPath = "";
        }
        for (QString &backupPath : backupFiles) {
            if (backupPath.startsWith(denyPath) || backupPath.startsWith(bindPath + denyPath)) {
                m_dataBackupWidget->setTips(tr("Backup and restore cannot access the data in %1").arg(denyPath));
                m_dataBackupWidget->setTipsStyleSheet("QLabel {"
                                                      "color: #FF5736;"
                                                      "}");
                return;
            }
        }
    }

    m_destUUID = m_dataBackupWidget->getDestDeviceUUID();
    if (m_destUUID.isEmpty()) {
        return;
    }

    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_dataBackupWidget->setTips(tips);
        m_dataBackupWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        qWarning()<<"onDataBackupCheckSpace, another task is running, operateID = "<<operateID
                  <<", opType = "<<opType<<", progress = "<<progress;
        return;
    }

    UserDataBackupRequest request;
    request.username = Utils::getUserName();
    request.operateID = QUuid::createUuid().toString();
    request.filesFrom = backupFiles;
    //m_excludeFileItems = m_dataBackupWidget->getExclude();
    request.destUUID = m_destUUID;
    request.remark = msg;
    m_curUserOpID = request.operateID;
    if (!m_destUUID.isEmpty()) {
        m_frameProxy->setMenuDisabled(true);
        m_frameProxy->setQuitMenuDisabled(true);
        m_frameProxy->setWindowFuncClose(false);
        m_dataBackupWidget->setButtonEnable(false);

        request.rootUUID = m_frameProxy->rootUUID();
        request.exclude = this->getUsrDataSpecialExcludes(); // 先获取特殊过滤项目，后面追加用户界面选择的
        m_excludes = request.exclude;
        m_dataBackupWidget->setTips(tr("Calculating file size..."));
        m_dataBackupWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #000000;"
                                                        "}");
        m_dataBackupWidget->startSpinner();
       // QJsonObject jsonObject = request.marshal();
        auto requestReply = m_recoveryInterface->CheckUserDataBackupSpace(request);
        requestReply.waitForFinished();
        if (!requestReply.isValid()) {
            m_curUserOpID.clear();
            m_dataBackupWidget->stopSpinner();
            m_dataBackupWidget->setTips(tr(""));
            m_dataBackupWidget->setButtonEnable(true);
            qCritical() << "CheckUserDataBackupSpace failed, err: " << requestReply.error();
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup), tr("DBus error, please try again"));
            return;
        }

        int retVal = requestReply.value();
        if (static_cast<int>(ErrorCode::NoWriteable) == retVal) {
            m_curUserOpID.clear();
            m_dataBackupWidget->stopSpinner();
            m_dataBackupWidget->setButtonEnable(true);
            m_dataBackupWidget->setTips(tr("Cannot back up data to the read-only device"));
            m_dataBackupWidget->setTipsStyleSheet("QLabel {"
                                                  "color: #FF5736;"
                                                  "}");
            m_frameProxy->setMenuDisabled(false);
            m_frameProxy->setQuitMenuDisabled(false);
            m_frameProxy->setWindowFuncClose(true);
            return;
        }

        if (requestReply.value() != OK) {
            qCritical()<<"CheckUserDataBackupSpace failed, val = "<<requestReply.value();
            m_curUserOpID.clear();
            m_dataBackupWidget->stopSpinner();
            m_dataBackupWidget->setTips(tr(""));
            m_dataBackupWidget->setButtonEnable(true);
            onShowResult(false, static_cast<int>(OperateType::UserDataBackup));
            return;
        }
    }
}

void BackupModule::onCheckSpace()
{
    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);
        // if (progress > 0) {
        //     tips = tr("another task(%1: %2%) is running, User: %3").arg(opTypeDes).arg(progress).arg(userName);
        // } else {
        //     tips = tr("another task(%1) is running, User: %2").arg(opTypeDes).arg(progress).arg(userName);
        // }
        m_userDataBackupSelectWidget->setTips(tips);
        m_userDataBackupSelectWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        qInfo()<<"onCheckSpace, another task is running, operateID = "<<operateID
               <<", opType = "<<opType<<", progress = "<<progress;
        return;
    }

    m_destUUID = m_userDataBackupSelectWidget->getDestDeviceUUID();
    QString destMountPoint;
    if(!Device::getMountPointByUUID(m_destUUID, destMountPoint)) {
        qWarning()<<"onCheckSpace call getMountPointByUUID failed, m_destUUID = "<<m_destUUID;
        return;
    }

    if (Device::isDeviceMountedReadOnly(destMountPoint)) {
        m_userDataBackupSelectWidget->setTips(tr("Cannot back up data to the read-only device"));
        m_userDataBackupSelectWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        return;
    }

    UserDataBackupRequest request;
    request.username = Utils::getUserName();
    request.operateID = QUuid::createUuid().toString();
    m_excludeFileItems = m_userDataBackupSelectWidget->getExclude();
    request.destUUID = m_destUUID;
    if (!m_destUUID.isEmpty()) {
        m_frameProxy->setMenuDisabled(true);
        m_frameProxy->setQuitMenuDisabled(true);
        m_frameProxy->setWindowFuncClose(false);
        m_userDataBackupSelectWidget->setNextBtnEnabled(false);

        request.rootUUID = m_frameProxy->rootUUID();
        request.exclude = this->getUsrDataSpecialExcludes(); // 先获取特殊过滤项目，后面追加用户界面选择的
        for (auto &f : m_excludeFileItems) {
            if (f.fileType == File) {
                //过滤文件
                request.exclude.append(QString("/%1").arg(f.fileName));
            } else {
                //过滤文件夹
                if (f.children.isEmpty()) {
                    request.exclude.append(QString("/%1").arg(f.fileName));
                } else {
                    for (auto &c : f.children) {
                        if (c.fileType == File) {
                            request.exclude.append(QString("/%1/%2").arg(f.fileName).arg(c.fileName));
                        } else {
                            request.exclude.append(QString("/%1/%2").arg(f.fileName).arg(c.fileName));
                        }

                    }
                }
            }
        }

        m_excludes = request.exclude;
        m_userDataBackupSelectWidget->setTips(tr("Calculating file size..."));
        m_userDataBackupSelectWidget->setTipsStyleSheet("QLabel {"
                                                        "color: #FF5736;"
                                                        "}");
        m_userDataBackupSelectWidget->startSpinner();
    //    QJsonObject jsonObject = request.marshal();
        auto requestReply = m_recoveryInterface->CheckUserDataBackupSpace(request);
        requestReply.waitForFinished();
        if (!requestReply.isValid()) {
            m_userDataBackupSelectWidget->stopSpinner();
            m_userDataBackupSelectWidget->setTips(tr(""));
            m_userDataBackupSelectWidget->setNextBtnEnabled(true);
        //    qCritical() << Q_FUNC_INFO << ", CheckUserDataBackupSpace failed, err: " << requestReply.error();
            onShowResult(false, static_cast<int>(OperateType::CheckUserDataBackupSpace), tr("DBus error, please try again"));
            return;
        }
        if (requestReply.value() != OK) {
            m_userDataBackupSelectWidget->stopSpinner();
            m_userDataBackupSelectWidget->setTips(tr(""));
            m_userDataBackupSelectWidget->setNextBtnEnabled(true);
            onShowResult(false, static_cast<int>(OperateType::CheckUserDataBackupSpace));
            return;
        }
    }
}

void BackupModule::showUserDataBackupWidget(const QString &comboBoxText)
{
    if (m_userDataBackupWidget == nullptr) {
        m_userDataBackupWidget = new UserDataBackupWidget();
        connect(m_userDataBackupWidget, &UserDataBackupWidget::cancel, this, &BackupModule::onBack);
        connect(m_userDataBackupWidget, &UserDataBackupWidget::start, this,
                &BackupModule::onStartDataBackup);
    }

    QList<FileItem> tmpFileItems = m_fileItems;
    for (auto excludeItem : m_excludeFileItems) {
        for (auto &item : tmpFileItems) {
            if (item == excludeItem) {
                if (excludeItem.children.isEmpty()) {
                    // 过滤整个一级文件夹
                    tmpFileItems.removeAll(excludeItem);
                    continue;
                }

                // 过滤一级文件夹下面的部分文件夹或者文件
                for (auto childExcludeItem : excludeItem.children) {
                    item.children.removeAll(childExcludeItem);
                }
            }
        }
    }

    m_userDataBackupWidget->setFiles(tmpFileItems);

    auto partitionReply = m_recoveryInterface->ListPartition(true);
    partitionReply.waitForFinished();
    if (!partitionReply.isValid()) {
        qCritical() << partitionReply.error();
        onShowResult(false, static_cast<int>(OperateType::UserDataBackup),
                     tr("DBus error, please try again"));
        return;
    }

    m_userDataBackupWidget->setComboBoxText(comboBoxText);
    m_userDataBackupWidget->setRemark(""); // clear
    m_frameProxy->setCurrentWidget(this, m_userDataBackupWidget);
}

void BackupModule::onReportCheckSpace(const QString &space)
{
    QJsonObject jsonObject = Utils::QStringToJson(space);
    int recoveryType = -1;
    if (jsonObject.contains("recoveryType")) {
        recoveryType = jsonObject.value("recoveryType").toInt(-1);
    }

    int errorCode = -1;
    if (jsonObject.contains("errCode")) {
        errorCode = jsonObject.value("errCode").toInt(-1);
    }

    int operateType = -1;
    if (jsonObject.contains("operateType")) {
        operateType = jsonObject.value("operateType").toInt(-1);
    }

    if (recoveryType == static_cast<int> (RecoveryType::Rsync) ||
        recoveryType == static_cast<int> (RecoveryType::OSTree)) {
        return this->systemBackup(operateType, errorCode);
    }
}

void BackupModule::systemBackup(int operateType, int errorCode)
{
    if (operateType == static_cast<int> (OperateType::CheckIncSystemBackupSpace)) {
        if (errorCode != OK) {
            m_frameProxy->setMenuDisabled(false);
            m_frameProxy->setQuitMenuDisabled(false);
            m_frameProxy->setWindowFuncClose(true);
            m_systemBackupWidget->setTips(
                    tr("Insufficient disk space. Please clean up first."));
            qCritical() << Q_FUNC_INFO << " systemBackup failed! errorCode = " << errorCode;
            return;
        }

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

        int replayValue = reply.value();
        if (replayValue != ErrorCode::OK) {
            //    qInfo()<<"SystemBackup replayValue = "<<replayValue;
            // TODO: 可以根据具体的错误码显示更详细的错误提示信息，先简单显示
            onShowResult(false, static_cast<int>(OperateType::SystemBackup),
                         tr("Sorry, backup failed!"));
            return;
        }

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