//
// Created by 张雪明 <zhangxueming@uniontech.com> on 2023/10/17.
//
#include "SysBackupWidgetV20.h"

#include "common/treeview.h"
#include "common/radioitem.h"
#include "common/treeviewmodel.h"
#include "common/settingsgroup.h"

#include <DFontSizeManager>
#include <DListView>
#include <DStandardItem>
#include <DWaterProgress>
#include <DHeaderView>

#include <QTreeView>
#include <QButtonGroup>
#include <QVBoxLayout>
#include <QLabel>
#include <DBackgroundGroup>
#include <QPushButton>
#include <QStandardItemModel>
#include <QDir>
#include <QTimer>
#include <QRadioButton>
#include<QSharedPointer>
#include <QProcess>
#include <DDialog>
#include <QDebug>
#include "utils/global.h"
#include "common/CommonFunc.h"

#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    #include <DPaletteHelper>
#else
    #include <DApplicationHelper>
#endif

using namespace Utils;

SysBackupWidgetV20::SysBackupWidgetV20(QWidget* parent)
        : QWidget(parent)
        , m_actionType(ActionType::SystemBackup)
        , m_backupType(BackupType::AddBackup)
        , m_directoryChooseWidget(new DFileChooserEdit)
        , m_tipsLabel(new DTipLabel)
        , m_backupBtn(new QPushButton(tr("Back Up")))
        , m_loadingWidget(new QWidget)
        , m_sysBackupItem(new RadioItem)
        , m_fullBackupItem(new RadioItem)
        , m_addBackupItem(new RadioItem)
        , m_coverBackupItem(new RadioItem)
        , m_treeView(new BaseTableTreeView)
        , m_treeViewModel(new TreeViewModel)
{
    this->setAccessibleName("uosBackupV20_SysBackupWidgetV20");
    QVBoxLayout* mainLayout = new QVBoxLayout;
    mainLayout->setContentsMargins(52, 20, 52, 0);
    mainLayout->setSpacing(10);

    DLabel *title = new DLabel;
    title->setText(tr("System backup"));
    title->setAccessibleName("uosBackupV20_SystemBackupLabel");
    title->setAlignment(Qt::AlignCenter);
    DFontSizeManager::instance()->bind(title, DFontSizeManager::T3);
    QFont font = title->font();
    font.setWeight(QFont::DemiBold);
    title->setFont(font);
    mainLayout->addWidget(title);
    mainLayout->addSpacing(20);
    m_backupBtn->setAccessibleName("SystemBackup_BackUp");
    SettingsGroup *settingsGrp = new SettingsGroup(nullptr, SettingsGroup::GroupBackground);
    SettingsGroup *backupTypeGrp = new SettingsGroup(false,nullptr, SettingsGroup::GroupBackground);
    settingsGrp->setAccessibleName("SystemBackup_settingsGrp");
    //backupTypeGrp->setBackgroundGroupAccessibleName("uosBackupV20_SystemBackup_backupTypeGrp");
    QLabel *backupType = new QLabel(tr("Backup Type"));
    backupType->setAccessibleName("SystemBackup_BackupType");
    QLabel *savePath = new QLabel(tr("Saving Method"));
    savePath->setAccessibleName("SystemBackup_SavingMethod");
    backupType->setContentsMargins(10, 0, 0, 0);
    savePath->setContentsMargins(10, 0, 0, 0);
    DFontSizeManager::instance()->bind(backupType, DFontSizeManager::T5, QFont::DemiBold);
    DFontSizeManager::instance()->bind(savePath, DFontSizeManager::T5, QFont::DemiBold);

    QWidget* backupTypeWidget = new QWidget;
    backupTypeWidget->setAccessibleName("SystemBackup_backupTypeWidget");
    QHBoxLayout *backupTypeHLayout = new QHBoxLayout(backupTypeWidget);
    backupTypeHLayout->setContentsMargins(0,0,0,0);
    QButtonGroup* backupTypeGroup = new QButtonGroup(backupTypeWidget);
    backupTypeGroup->setExclusive(true);
    backupTypeGroup->addButton(m_sysBackupItem->radioButton());
    backupTypeGroup->addButton(m_fullBackupItem->radioButton());
    m_sysBackupItem->radioButton()->setChecked(true);
    m_sysBackupItem->setTitle(tr("System Backup"));
    m_sysBackupItem->setAccessibleName("uosBackupV20_SystemBackup_SystemBackupItem");
    m_sysBackupItem->setRadioButtonAccessibleName("SystemBackup_SystemBackupRadioButton");
    m_sysBackupItem->setRadioButtonToolTip(tr("The data in the boot partition (/boot), root partition (/) and directories /opt and /var will be backed up."));
    m_fullBackupItem->setTitle(tr("Full Backup"));
    m_fullBackupItem->setAccessibleName("SystemBackup_FullBackupItem");
    m_fullBackupItem->setRadioButtonAccessibleName("SystemBackup_FullBackupRadioButton");
    m_fullBackupItem->setRadioButtonToolTip(tr("Data in all partitions will be backed up."));
    backupTypeGrp->appendItem(m_sysBackupItem);
    backupTypeGrp->appendItem(m_fullBackupItem);
    backupTypeGrp->setAccessibleName("SystemBackup_backupTypeGrp");
    backupTypeHLayout->addWidget(m_sysBackupItem);
    backupTypeHLayout->addSpacing(140);
    backupTypeHLayout->addWidget(m_fullBackupItem);

    //设置互斥
    QButtonGroup* buttonGroup = new QButtonGroup;
    buttonGroup->setExclusive(true);
    buttonGroup->addButton(m_addBackupItem->radioButton());
    buttonGroup->addButton(m_coverBackupItem->radioButton());
    m_addBackupItem->radioButton()->setChecked(true);

    //新增备份
    {
        QHBoxLayout* chooseLayout = new QHBoxLayout;
        chooseLayout->setContentsMargins(contentMargin, contentMargin, contentMargin, contentMargin);
#if DTK_VERSION >= DTK_VERSION_CHECK(5, 2, 2, 13)
        m_directoryChooseWidget->setPlaceholderText(tr("Select a path to save backup files"));
#endif
        m_directoryChooseWidget->setAccessibleName("SystemBackup_SelectAPathToSaveBackupFiles");
        m_directoryChooseWidget->lineEdit()->setAccessibleName("SystemBackup_directoryChooseWidgetlineEdit");
        chooseLayout->addWidget(m_directoryChooseWidget, 0, Qt::AlignVCenter);
        QWidget* bgWidget = new QWidget;
        bgWidget->setLayout(chooseLayout);
        m_addBackupItem->setContent(bgWidget);
        m_addBackupItem->setTitle(tr("New Backup"));
        m_addBackupItem->setRadioButtonAccessibleName("SystemBackup_NewBackupRadioButton");
        m_addBackupItem->setAccessibleName("SystemBackup_NewBackupAddBackupItemGrp");

        settingsGrp->appendItem(m_addBackupItem);
    }

    //覆盖备份
    {
        QVBoxLayout* chooseLayout = new QVBoxLayout;
        chooseLayout->setContentsMargins(contentMargin, contentMargin, contentMargin, contentMargin);
        m_treeView->setModel(m_treeViewModel);
        m_treeView->setAccessibleName("SystemBackup_SystemIncrementalBackupTreeView");
        chooseLayout->addWidget(m_treeView);

        m_defaultWidget = new QWidget;
        m_defaultWidget->setLayout(chooseLayout);

        bgWidget = new QWidget;
        bgWidget->setLayout(chooseLayout);
        bgWidget->setMaximumHeight(120);
        m_coverBackupItem->setTitle(tr("System Incremental Backup"));
        m_coverBackupItem->setContent(bgWidget);
        m_coverBackupItem->setRadioButtonAccessibleName("SystemBackup_SystemIncrementalBackupRadioButton");
        m_coverBackupItem->setAccessibleName("SystemBackup_NewBackupCoverBackupItemGrp");
        settingsGrp->appendItem(m_coverBackupItem);
    }
    //cover非选中状态时
    if(!m_coverBackupItem->checked()) {
        m_coverBackupItem->getContent()->setHidden(true);
    }

    //设置按宽度
    m_backupBtn->setMinimumSize(240,36);

    mainLayout->setSpacing(5);  //设置标题和内容的间距
    mainLayout->addWidget(backupType, 0);
    mainLayout->addWidget(backupTypeWidget, 0, Qt::AlignLeft);
    mainLayout->addSpacing(20);
    mainLayout->addWidget(savePath, 0, Qt::AlignLeft);
    mainLayout->addWidget(settingsGrp);
    mainLayout->addWidget(m_tipsLabel);
    mainLayout->addStretch();
    mainLayout->addWidget(m_loadingWidget, 0, Qt::AlignCenter);
    mainLayout->addStretch();
    mainLayout->addWidget(m_backupBtn, 0, Qt::AlignCenter);

    setLayout(mainLayout);

    if (nullptr != m_directoryChooseWidget) {
        m_directoryChooseWidget->setFileMode(QFileDialog::Directory);
    }

    //设置初始行宽
    connect(m_treeViewModel, &TreeViewModel::itemsIsReady, this, [this]{
        setColumnWidth();
    });

    connect(m_directoryChooseWidget, &DFileChooserEdit::dialogClosed, this, &SysBackupWidgetV20::onChoose);
    connect(m_backupBtn, &QPushButton::clicked, this, &SysBackupWidgetV20::backup, Qt::QueuedConnection);
    connect(m_directoryChooseWidget->lineEdit(), &QLineEdit::textChanged, this, [ = ](const QString& text) {
        m_backupBtn->setEnabled(!text.isEmpty());
    });


    connect(backupTypeGroup, QOverload<QAbstractButton*, bool>::of(&QButtonGroup::buttonToggled),
            this, &SysBackupWidgetV20::onBackupTypeButtonGroupToggled);
    connect(buttonGroup, QOverload<QAbstractButton*, bool>::of(&QButtonGroup::buttonToggled), this,
            [this](QAbstractButton *button, bool checked){
                auto setItemStatus = [](RadioItem* item) {
                    item->radioButton()->blockSignals(true);
                    item->setChecked(true);
                    item->radioButton()->blockSignals(false);
                    // item->getContent()->setHidden(false);
                };

                if (checked) {
                    setTipsVisible(false);
                    // m_coverBackupItem->getContent()->setHidden(true);
                    QRadioButton* radioButton = qobject_cast<QRadioButton*> (button);
                    m_backupBtn->setEnabled(false);
                    if(radioButton == m_addBackupItem->radioButton()){
                        m_backupType = BackupType::AddBackup;
                        setItemStatus(m_addBackupItem);
                        m_coverBackupItem->setContent(m_defaultWidget);
                        m_coverBackupItem->getContent()->setHidden(false);
                        m_backupBtn->setEnabled(!m_directoryChooseWidget->lineEdit()->text().isEmpty());
                    }else if (radioButton == m_coverBackupItem->radioButton()) {
                        m_backupType = BackupType::CoverBackup;
                        setItemStatus(m_coverBackupItem);
                        m_coverBackupItem->setContent(bgWidget);
                        m_coverBackupItem->getContent()->setHidden(false);
                        //Q_EMIT requestTreeViewListItem(m_treeViewModel);
                        processTreeViewListItem(m_treeViewModel);
                    }
                }
            });
    connect(m_treeView, &QTreeView::clicked, this, [this](const QModelIndex &index){
        setTipsVisible(false);
        for (int i=0; i < m_treeViewModel->rowCount(); ++i) {
            m_treeViewModel->item(i,1)->setCheckState(Qt::Unchecked);
        }
        m_treeViewModel->item(index.row(), 1)->setCheckState(Qt::Checked);
    });
    //设置按钮点击
    connect(m_treeView, &QTreeView::clicked, this, [this](const QModelIndex &index){
        if (!index.isValid()) {
            m_backupBtn->setEnabled(false);
        } else {
            QModelIndex currentIndex = index.sibling(index.row(), 0);
            QString choosePath = m_treeView->model()->itemData(currentIndex).values()[0].toString();
            if (choosePath.isEmpty()) {
                m_backupBtn->setEnabled(false);
            } else {
                m_backupBtn->setEnabled(true);
            }
        }
    });

    m_backupBtn->setEnabled(false);

    m_loadingWidget->setVisible(false);
    initUI();
    //QTimer::singleShot(0, this, &SysBackupWidgetV20::initUI);
}

void SysBackupWidgetV20::setTipsLabelText(const QString &msg)
{
    if (nullptr != m_tipsLabel) {
        m_tipsLabel->setText(msg);
    }
}

void SysBackupWidgetV20::processTreeViewListItem(TreeViewModel *model)
{
    model->clear();

    // 读取savePath.json
    const QString &savePath = "/recovery/backup/savePath.json";
    QList<BackupFileInfo> backupList;
    Common::getHistoryBackup(backupList, savePath, false);

    for (auto &info : backupList) {
        model->appendRow({new QStandardItem(info.backupFullPath), new QStandardItem(info.backupTime)});
    }

    if (backupList.isEmpty()) {
        model->appendRow({new QStandardItem(""), new QStandardItem("")});
        model->appendRow({new QStandardItem(""), new QStandardItem("")});
    }

    Q_EMIT model->itemsIsReady();
}

void SysBackupWidgetV20::onBackupTypeButtonGroupToggled(QAbstractButton *button, bool checked)
{
    m_tipsLabel->hide();
    if (checked) {
        QRadioButton* radioButton = qobject_cast<QRadioButton*> (button);
        if(radioButton == m_sysBackupItem->radioButton()){
            m_actionType = ActionType::SystemBackup;
            m_addBackupItem->radioButton()->blockSignals(true);
            m_addBackupItem->setChecked(true);
            m_addBackupItem->radioButton()->blockSignals(false);
            
            m_coverBackupItem->setContent(bgWidget);
            m_coverBackupItem->getContent()->setHidden(true);
            m_coverBackupItem->setHidden(false);
        }else if (radioButton == m_fullBackupItem->radioButton()) {
            m_actionType = ActionType::ManualBackup;
            m_coverBackupItem->setContent(m_defaultWidget);
            m_coverBackupItem->getContent()->setHidden(false);
            m_coverBackupItem->setHidden(true);
        }
    }
}

void SysBackupWidgetV20::initUI()
{
    m_tipsLabel->setWordWrap(true);
#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    DPalette pa = DPaletteHelper::instance()->palette(m_tipsLabel);
#else
    DPalette pa = DApplicationHelper::instance()->palette(m_tipsLabel);
#endif
 //   auto pa = DApplicationHelper::instance()->palette(m_tipsLabel);
    pa.setBrush(DPalette::TextTips, Qt::red);
#if DTK_VERSION >= DTK_VERSION_CHECK(5, 5, 10, 0)
    DPaletteHelper::instance()->setPalette(m_tipsLabel, pa);
#else
    DApplicationHelper::instance()->setPalette(m_tipsLabel, pa);
#endif

    m_tipsLabel->hide();

    QVBoxLayout* loadingLayout = new QVBoxLayout;
    m_loadingWidget->setLayout(loadingLayout);
    m_loadingWidget->setAccessibleName("SystemBackup_loadingWidget");

    DWaterProgress* loadingIndicator = new DWaterProgress;
    loadingLayout->addWidget(loadingIndicator, 0, Qt::AlignHCenter);
    loadingIndicator->setAccessibleName("SystemBackup_DWaterProgress");
    loadingIndicator->setValue(50);
    loadingIndicator->setTextVisible(false);
    loadingIndicator->setFixedSize(48, 48);
    loadingIndicator->start();

    QLabel* tips = new QLabel(tr("Applying changes to your system..."));
    tips->setAccessibleName("SystemBackup_ApplyingChangesToYourSystem");
    loadingLayout->addWidget(tips);
}

void SysBackupWidgetV20::setTipsVisible(const bool &visible)
{
    m_tipsLabel->setVisible(visible);
}

void SysBackupWidgetV20::setFileDialog(QFileDialog *fileDialog)
{
    if (nullptr != m_directoryChooseWidget) {
        m_directoryChooseWidget->setFileDialog(fileDialog);
    }
}

void SysBackupWidgetV20::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);
    setColumnWidth();
}

void SysBackupWidgetV20::onBackupButtonVisibleChanged(bool value)
{
    m_backupBtn->setVisible(value);
    m_loadingWidget->setVisible(!value);
}

void SysBackupWidgetV20::onChoose(const int &code)
{
    if (code == QDialog::Accepted) {
        m_tipsLabel->hide();
    }

    // TODO(justforlxz): need send signal to worker -> model;
    m_backupBtn->setEnabled(!m_directoryChooseWidget->lineEdit()->text().isEmpty());
}

void SysBackupWidgetV20::backup()
{
    m_tipsLabel->hide();
    QString choosePath;

    switch (m_backupType) {
        case BackupType::AddBackup:
            choosePath = m_directoryChooseWidget->lineEdit()->text();
            break;
        case BackupType::CoverBackup: {
            QModelIndex currentIndex = m_treeView->currentIndex();
            currentIndex = currentIndex.sibling(currentIndex.row(), 0);
            choosePath = m_treeView->model()->itemData(currentIndex).values()[0].toString();
            //特殊标记为备份点备份文件
            choosePath += "#";
            break;
        }
        default:
            break;
    }

    if (!choosePath.isEmpty()) {
        setFocus();
        m_backupBtn->setVisible(false);
        m_loadingWidget->setVisible(true);
        if (m_actionType == ActionType::ManualBackup) {
            Q_EMIT requestSetManualBackupDirectory(choosePath);
        } else {
            Q_EMIT requestSetSystemBackupDirectory(choosePath);
        }
    }
}

void SysBackupWidgetV20::setColumnWidth()
{
    const int width = m_coverBackupItem->width() - 2 * strechSpace - timeFieldStretchWidth;
    int defaultWidth = 556; // 界面实际大概 517
    if (nullptr != m_treeView) {
        if (m_treeViewModel->rowCount()) {
            m_treeView->setColumnWidth(0, width);
        } else {
            m_treeView->setColumnWidth(0, defaultWidth);
        }
    }
}

void SysBackupWidgetV20::onManualBackupErrorTypeChanged(ErrorType type)
{
    m_tipsLabel->setVisible(true);

    switch (type) {
        case ErrorType::LocationError: {
            m_tipsLabel->setText(tr("The storage location cannot be in source disk, please reselect"));
            break;
        }
        case ErrorType::PathError: {
            m_tipsLabel->setText(tr("Invalid path"));
            break;
        }
        case ErrorType::SpaceError: {
            m_tipsLabel->setText(tr("Insufficient disk space"));
            break;
        }
        case ErrorType::FsError: {
            m_tipsLabel->setText(tr("The file system is not supported for backup. Please select one in ext4, btrfs, xfs, reiserfs format."));
            break;
        }
        case ErrorType::DeviceReadOnly: {
            m_tipsLabel->setText(tr("Cannot back up data to the read-only device"));
            break;
        }
        case ErrorType::BackupPathError: {
            m_tipsLabel->setText(tr("This directory cannot be used to store backup files, please select a different directory."));
            break;
        }
        default: {
            m_tipsLabel->setVisible(false);
            break;
        }
    }
}

void SysBackupWidgetV20::doSuccess()
{
    int result = -1;
    DDialog dialog(this);
    dialog.setIcon(QIcon::fromTheme("dialog-warning"));
    dialog.addButton(tr("Cancel", "button"));
    dialog.setMessage(tr("System backup is ready. Do you want to reboot and backup your system now?"));
    result = dialog.addButton(tr("Reboot and Backup"), true, DDialog::ButtonWarning);
    dialog.setAccessibleName("SysBackupWidget_doSuccessDDialog");
    dialog.getButton(0)->setAccessibleName("doSuccessDDialog_Cancel");
    dialog.getButton(1)->setAccessibleName("doSuccessDDialog_RebootAndBackup");
    QRect rect = geometry();
    dialog.move(rect.center());
    dialog.moveToCenter();

    if (dialog.exec() != result) {
        Q_EMIT cancelBackup();
        return;
    }

    Q_EMIT requestReboot();
    // qDebug() << Q_FUNC_INFO <<", RestorePage::onCancelRestore reboot now";
    // Utils::reboot(true, false);
}

void SysBackupWidgetV20::cancelBackupSuccess()
{
    if (nullptr != m_tipsLabel) {
        m_tipsLabel->setText("");
        m_tipsLabel->setVisible(false);
    }

    if (nullptr != m_loadingWidget) {
        m_loadingWidget->setVisible(false);
    }

    if (nullptr != m_backupBtn) {
        m_backupBtn->setVisible(true);
    }
}

void SysBackupWidgetV20::doError(int errCode)
{
    if (nullptr != m_loadingWidget) {
        m_loadingWidget->setVisible(false);
    }
    m_backupBtn->setVisible(true);

    ErrorType type = static_cast<ErrorType>(errCode);
    onManualBackupErrorTypeChanged(type);
}

int doCancelBackup()
{
    QStringList args;
    args<<"/bin/deepin-recovery-tool" << "-a" << "cancel_backup";
    QSharedPointer<QProcess> process(new QProcess);
    process->start("pkexec", args);
    // pkexec提权操作不能自动超时，应等待用户输入密码完成，或放弃输入密码
    process->waitForFinished(-1);

    const int &exitCode = process->exitCode();
    QString error = process->readAllStandardError();
    qDebug() <<Q_FUNC_INFO << "doCancelBackup, exitCode:" << exitCode<<", args: "<<args<<", error: "<<error;

    return exitCode;
}

void SysBackupWidgetV20::onCancelBackup()
{
    int result = -1;
    DDialog dialog(this);
    dialog.setIcon(QIcon::fromTheme("dialog-warning"));
    dialog.addButton(tr("Cancel", "button"));
    dialog.setMessage(tr("System backup is ready. Do you want to reboot and backup your system now?"));
    result = dialog.addButton(tr("Reboot and Backup"), true, DDialog::ButtonWarning);
    dialog.setAccessibleName("SysBackupWidget_CancelBackupDDialog");
    dialog.getButton(0)->setAccessibleName("CancelBackupDDialog_Cancel");
    dialog.getButton(1)->setAccessibleName("CancelBackupDDialog_RebootAndBackup");
    QRect rect = geometry();
    dialog.move(rect.center());
    dialog.moveToCenter();

    if (dialog.exec() != result) {
        doCancelBackup();
        return;
    }

    qDebug() << Q_FUNC_INFO <<", RestorePage::onCancelRestore reboot now";
    Utils::reboot(true, false);
}

void SysBackupWidgetV20::setEnableInHighSysLevelMode(bool enable)
{
    if (nullptr != m_backupBtn) {
        m_backupBtn->setEnabled(enable);
    }

    if (nullptr != m_sysBackupItem) {
        m_sysBackupItem->setEnabled(enable);
    }

    if (nullptr != m_fullBackupItem) {
        m_fullBackupItem->setEnabled(enable);
    }

    if (nullptr != m_addBackupItem) {
        m_addBackupItem->setEnabled(enable);
    }

    if (nullptr != m_coverBackupItem) {
        m_coverBackupItem->setEnabled(enable);
    }
}
