//
// Created by 张雪明 <zhangxueming@uniontech.com> on 2023/10/18.
//
#include "SysRestoreWidgetV20.h"
#include <DFontSizeManager>
#include <DPaletteHelper>
#include <DFrame>
#include <DWaterProgress>
#include <dfilechooseredit.h>
#include <DTipLabel>

#include <QVBoxLayout>
#include <QLabel>
#include <DBackgroundGroup>
#include <QPushButton>
#include <QDir>
#include <QRadioButton>
#include <QCheckBox>
#include <QFile>
#include <QSettings>
#include <QDebug>
#include <QSharedPointer>
#include <DDialog>
#include <DDBusSender>
#include <QCryptographicHash>
#include <QTimer>
#include<QSharedPointer>
#include <QProcess>
#include <DDialog>
#include "common/treeview.h"
#include "common/radioitem.h"
#include "common/treeviewmodel.h"
#include "common/settingsgroup.h"
#include "common/CommonFunc.h"

using namespace Utils;

SysRestoreWidgetV20::SysRestoreWidgetV20(QWidget *parent)
        : QWidget(parent)
        , m_saveUserDataCheckBox(new QCheckBox)
        , m_directoryChooseWidget(new DFileChooserEdit)
        , m_tipsLabel(new DTipLabel)
        , m_backupBtn(new QPushButton(tr("Restore Now")))
        , m_systemRestore(new RadioItem)
        , m_manualRestore(new RadioItem)
        , m_coverRestore(new RadioItem)
        , m_loadingWidget(new QWidget)
        , m_treeView(new BaseTableTreeView)
        , m_treeViewModel(new TreeViewModel(this))
        , m_settingsGrp(new SettingsGroup(nullptr, SettingsGroup::GroupBackground))
        , m_actionType(ActionType::InitialRestore)
{
    this->setAccessibleName("uosRestoreV20_SysRestoreWidgetV20");
    m_backupBtn->setAccessibleName("SystemRestore_RestoreNow");
    QVBoxLayout* mainLayout = new QVBoxLayout;
    mainLayout->setContentsMargins(62, 20, 62, 0);

    DLabel *title = new DLabel;
    title->setText(tr("System Restore"));
    title->setAccessibleName("uosRestoreV20_SystemRestoreLabel");
    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_subTitle = new DLabel;
    m_subTitle->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    m_subTitle->setText(tr("Please choose the restore method"));
    m_subTitle->setAccessibleName("uosRestoreV20_PleaseChooseTheRestoreMethod");
    QFont subTitleFont = m_subTitle->font();
    subTitleFont.setPixelSize(14);
    subTitleFont.setWeight(QFont::DemiBold);
    m_subTitle->setFont(subTitleFont);
    DFontSizeManager::instance()->bind(m_subTitle, DFontSizeManager::T6);
    QPalette subTitlePalette;
    subTitlePalette.setColor(QPalette::BrightText, QColor(qRgba(0,0,0,0.85)));
    m_subTitle->setPalette(subTitlePalette);
    mainLayout->addWidget(m_subTitle);
    mainLayout->addSpacing(15);

    mainLayout->addWidget(m_settingsGrp);

    // manual restore
    {
        QHBoxLayout* chooseLayout = new QHBoxLayout;
        chooseLayout->setContentsMargins(contentMargin, contentMargin, contentMargin, contentMargin);
#if DTK_VERSION >= DTK_VERSION_CHECK(5, 2, 2, 13)
        m_directoryChooseWidget->setPlaceholderText(tr("Backup directory"));
#endif
        m_directoryChooseWidget->setAccessibleName("SystemRestore_BackupDirectory");
        m_directoryChooseWidget->lineEdit()->setAccessibleName("SystemRestore_directoryChooseWidgetlineEdit");
        chooseLayout->addWidget(m_directoryChooseWidget, 0, Qt::AlignVCenter);

        QWidget* bgWidget = new QWidget;
        bgWidget->setLayout(chooseLayout);

        m_manualRestore->setContent(bgWidget);
        m_manualRestore->setTitle(tr("Restore from backup file"));
        m_manualRestore->setAccessibleName("SystemRestore_manualRestoreGrp");
        m_manualRestore->setRadioButtonAccessibleName("SystemRestore_RestoreFromBackupFileRadioButton");

        m_settingsGrp->appendItem(m_manualRestore);
    }
    // manual restore end

    //cover restore start
    {
        QHBoxLayout* chooseLayout = new QHBoxLayout;
        chooseLayout->setContentsMargins(contentMargin, contentMargin, contentMargin, contentMargin);
        m_treeView->setModel(m_treeViewModel);
        chooseLayout->addWidget(m_treeView);

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

        bgWidget =new QWidget;
        bgWidget->setLayout(chooseLayout);
        bgWidget->setMaximumHeight(130);

        m_coverRestore->setContent(bgWidget);
        m_coverRestore->setTitle(tr("Restore from a restore point"));
        m_coverRestore->setAccessibleName("SystemRestore_coverRestoreGrp");
        m_coverRestore->setRadioButtonAccessibleName("SystemRestore_RestoreFromARestorePointRadioButton");

        m_settingsGrp->appendItem(m_coverRestore);
    }
    //cover restore end

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

    mainLayout->addWidget(m_tipsLabel);
    mainLayout->addStretch();
    mainLayout->addWidget(m_loadingWidget, 0, Qt::AlignCenter);
    mainLayout->addStretch();
    mainLayout->addWidget(m_backupBtn, 0, Qt::AlignCenter);

    setLayout(mainLayout);

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

    connect(m_directoryChooseWidget, &DFileChooserEdit::dialogClosed, this, [this] (const int &code) {
        if (code == QDialog::Accepted) {
            m_tipsLabel->hide();
        }
    });
    connect(m_directoryChooseWidget, &DFileChooserEdit::textChanged, this, [this] (const QString &path) {
        QDir dir(path);
        if (!dir.exists()) {
            m_backupBtn->setEnabled(false);
            return;
        }
        for (const QFileInfo &fileInfo : dir.entryInfoList(QDir::Files)) {
            if (fileInfo.suffix() == "dim") {
                m_backupBtn->setEnabled(true);
                return;
            }
        }
        m_backupBtn->setEnabled(false);
    });
    connect(m_backupBtn, &QPushButton::clicked, this, &SysRestoreWidgetV20::restore, Qt::QueuedConnection);
    connect(m_systemRestore->radioButton(), &QRadioButton::toggled, this, &SysRestoreWidgetV20::onItemChecked);
    connect(m_manualRestore->radioButton(), &QRadioButton::toggled, this, &SysRestoreWidgetV20::onItemChecked);
    connect(m_coverRestore->radioButton(), &QRadioButton::toggled, this, &SysRestoreWidgetV20::onItemChecked);

    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);
        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_loadingWidget->setVisible(false);
    m_directoryChooseWidget->setFileMode(QFileDialog::Directory);

    initUI();
}

void SysRestoreWidgetV20::initDFileChooserEdit()
{
    if (nullptr != m_directoryChooseWidget) {
        m_directoryChooseWidget->setFileMode(QFileDialog::Directory);
        m_directoryChooseWidget->setText("");
    }
}

void SysRestoreWidgetV20::initUI()
{
    m_tipsLabel->setWordWrap(true);
    DPalette pa = DPaletteHelper::instance()->palette(m_tipsLabel);
    pa.setBrush(DPalette::TextTips, Qt::red);
    DPaletteHelper::instance()->setPalette(m_tipsLabel, pa);

    m_tipsLabel->hide();

    m_manualRestore->radioButton()->setChecked(true);

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

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

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

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

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

void SysRestoreWidgetV20::setFileDialog(QFileDialog *fileDialog)
{
    m_directoryChooseWidget->setFileDialog(fileDialog);
}

void SysRestoreWidgetV20::addTitleLabel()
{
    QLabel *titleLabel = new QLabel(tr("Restore"));
    DFontSizeManager::instance()->bind(titleLabel, DFontSizeManager::T1);

    QVBoxLayout *mainLayout(reinterpret_cast<QVBoxLayout *>(layout()));
    mainLayout->insertWidget(0, titleLabel, 0, Qt::AlignHCenter);
    mainLayout->insertSpacing(1, 10);
}

void SysRestoreWidgetV20::setDevicePage()
{
    m_settingsGrp->clear();
    if (nullptr != m_manualRestore) {
        delete m_manualRestore;
        m_manualRestore = nullptr;
    }

    if (nullptr != m_coverRestore) {
        delete m_coverRestore;
        m_coverRestore = nullptr;
    }
    m_systemRestore = new RadioItem;
    m_systemRestore->setTitle(tr("Reset to factory settings"));
    m_systemRestore->setTipText(tr("The initial backup file does not exist, so your system cannot be reset to factory settings."));
    connect(m_systemRestore->radioButton(), &QRadioButton::clicked, this, [this] {
        m_systemRestore->radioButton()->setChecked(true);
        if (!m_saveUserDataCheckBox->isChecked()) {
            m_saveUserDataCheckBox->setChecked(true);
        }
    });

    m_systemRestore->radioButton()->setChecked(true);
    m_saveUserDataCheckBox = new QCheckBox(this);
    m_saveUserDataCheckBox->setMinimumSize(24, 24);
    m_saveUserDataCheckBox->setChecked(true);
    m_saveUserDataCheckBox->setFocusPolicy(Qt::NoFocus);

    QVBoxLayout* chooseLayout = new QVBoxLayout;
    chooseLayout->setContentsMargins(28, 0, 0, 0);
    chooseLayout->addWidget(m_saveUserDataCheckBox);
    m_saveUserDataCheckBox->setText(tr("Keep personal files and apps"));

    QWidget* bgWidget = new QWidget;
    bgWidget->setLayout(chooseLayout);

    m_systemRestore->setContent(bgWidget);
    m_settingsGrp->appendItem(m_systemRestore);
//    qDeleteAll(m_systemRestore->getContent()->findChildren<QObject *>());
}

void SysRestoreWidgetV20::showEvent(QShowEvent *event)
{
    if (nullptr != m_manualRestore) {
        auto manualRestoreRadioBtn = m_manualRestore->radioButton();
        if (nullptr != manualRestoreRadioBtn) {
            manualRestoreRadioBtn->setFocusPolicy(Qt::NoFocus);
        }
    }

    if (nullptr != m_systemRestore) {
        auto systemRestoreRadioBtn = m_systemRestore->radioButton();
        if (nullptr != systemRestoreRadioBtn) {
            systemRestoreRadioBtn->setFocusPolicy(Qt::NoFocus);
        }
    }

    if (nullptr != m_coverRestore) {
        auto coverRestoreRadioBtn = m_coverRestore->radioButton();
        if (nullptr != coverRestoreRadioBtn) {
            coverRestoreRadioBtn->setFocusPolicy(Qt::NoFocus);
        }
    }

    QWidget::showEvent(event);
}

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

void SysRestoreWidgetV20::setColumnWidth()
{
    if (nullptr == m_coverRestore) {
        return;
    }

    const int width = m_coverRestore->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 SysRestoreWidgetV20::onSystemRestoreItemVisibelChanged(bool value)
{
    m_systemRestore->setRadioVisible(value);
    if (!value && m_settingsGrp->itemCount() == 1) { //当只有系统还原并没有初始化备份时，需要禁掉按钮
        m_backupBtn->setEnabled(false);
    }
}

void SysRestoreWidgetV20::onRestoreButtonVisibleChanged(bool value)
{
    m_backupBtn->setVisible(value);
    m_loadingWidget->setVisible(!value);
}

bool SysRestoreWidgetV20::isExistDim(const QString &path)
{
    if (path.isEmpty()) {
        return false;
    }

    QDir dir(path);
    if (!dir.exists()) {
        return false;
    }

    for (const QFileInfo &fileInfo : dir.entryInfoList(QDir::Files)) {
        if (fileInfo.suffix() == "dim") {
            return true;
        }
    }

    return false;
}

void SysRestoreWidgetV20::onItemChecked()
{
    setTipsVisible(false);
    QRadioButton* button = qobject_cast<QRadioButton*>(sender());

    auto setCheck = [](RadioItem* item, bool c) {
        item->radioButton()->blockSignals(true);
        item->setChecked(c);
        item->radioButton()->blockSignals(false);
    };

    setCheck(m_manualRestore, false);
   // setCheck(m_systemRestore, false);
    setCheck(m_coverRestore, false);
    m_backupBtn->setEnabled(false);
    // m_coverRestore->getContent()->setHidden(true);

    //m_saveUserDataCheckBox->setChecked(false);
    if (button == m_manualRestore->radioButton()) {
        setCheck(m_manualRestore, true);
        m_actionType = ActionType::ManualRestore;
        m_coverRestore->setContent(m_defaultWidget);
        m_coverRestore->getContent()->setHidden(false);
        bool existDim = isExistDim(m_directoryChooseWidget->text());
        m_backupBtn->setEnabled(existDim);
    } else {
        setCheck(m_coverRestore, true);
        m_coverRestore->setContent(bgWidget);
        m_coverRestore->getContent()->setHidden(false);
        m_coverRestore->getContent()->setContentsMargins(0,0,0,10);
        //m_actionType = ActionType::CoverRestore;
        m_actionType = ActionType::SystemRestore;
        //Q_EMIT requestTreeViewListItem(m_treeViewModel);
        processTreeViewListItem(m_treeViewModel);
    }
}

void SysRestoreWidgetV20::showHistoryBackup()
{
    if (m_coverRestore->checked()) {
        m_coverRestore->getContent()->setHidden(false);
        m_coverRestore->getContent()->setContentsMargins(0,0,0,10);
        m_backupBtn->setEnabled(false);
        m_actionType = ActionType::SystemRestore;
        processTreeViewListItem(m_treeViewModel);
    }
}

void SysRestoreWidgetV20::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 SysRestoreWidgetV20::onManualRestoreErrorChanged(ErrorType errorType)
{
    m_tipsLabel->setVisible(true);

    switch (errorType) {
        case ErrorType::MD5Error: {
            if (m_actionType == ActionType::InitialRestore)
                m_tipsLabel->setText(tr("The initial backup file is broken, so your system cannot be reset to factory settings."));
            else
                m_tipsLabel->setText(tr("Backup file is invalid"));
            break;
        }
        case ErrorType::PathError: {
            m_tipsLabel->setText(tr("Invalid path"));
            break;
        }
        default: {
            m_tipsLabel->setVisible(false);
            break;
        }
    }
}

void SysRestoreWidgetV20::restore()
{
    m_tipsLabel->hide();
    // if (nullptr != m_coverRestore) {
    //     m_coverRestore->getContent()->setHidden(true);
    // }

    if (m_actionType == ActionType::InitialRestore) {
        const bool formatData = !m_saveUserDataCheckBox->isChecked();
        DDialog dialog(this);
        dialog.setIcon(QIcon::fromTheme("dialog-warning"));

        if (formatData) {
            dialog.setFixedSize(450, 240);
            dialog.setTitle(tr("Reset to Factory Settings"));
            dialog.setMessage(tr("It will permanently clear data of all users on this device, please confirm before proceeding"));
        } else {
            dialog.setTitle(tr("Keep Personal Files"));
            QString msg = tr("It will reset data on your system disk but keep your personal data. You need to create an account with the same username as the current user so that you can access your personal data later. Please confirm before proceeding.");
            int msgSize = msg.length();
            int minSize = 11; // 控制中心最小字号是11
            int normalMaxFontHeight = 31; // 控制中心字号20，对应的中文的字体高度
            QFont font = dialog.font();
            QFontMetrics fontMetrics(font);
            int fontSize = font.pointSize();
            int diffHeight = fontMetrics.height() - normalMaxFontHeight;
            // msgSize diffHeight 来调整藏语等翻译后文案比较长，字体高度比较高
            int width = 420 + (fontSize - minSize) * 10 + diffHeight * 5 + (msgSize < 100 ? 0 : 50);
            int height = 230 + (fontSize - minSize) * 10 + (diffHeight <= 0 ? diffHeight : diffHeight * 4) + (msgSize < 100 ? 0 : 60);
            dialog.setFixedSize(width, height);
            dialog.setMessage(msg);
        }

        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);
            dialog.setAccessibleName("SysRestoreWidget_restoreDialog");
            dialog.getButton(0)->setAccessibleName("SysRestoreWidget_restoreDialogCancel");
            dialog.getButton(1)->setAccessibleName("SysRestoreWidget_restoreDialogConfirmAndReset");
            if (dialog.exec() != result) {
                return;
            }
        }

        Q_EMIT requestSystemRestore(formatData);
        m_loadingWidget->setVisible(true);
        m_backupBtn->setVisible(false);
    }

    if (m_actionType == ActionType::ManualRestore) {
        // TODO(justforlxz): 判断内容的有效性
        const QString& selectPath = m_directoryChooseWidget->lineEdit()->text();

        if (selectPath.isEmpty()) {
            // TODO(justforlxz): 这里要更换成相应的错误，应该是ErrorType::PathError
            return onManualRestoreErrorChanged(ErrorType::MD5Error);
        }

        Q_EMIT requestManualRestore(selectPath);
        m_loadingWidget->setVisible(true);
        m_backupBtn->setVisible(false);
    }

    if (m_actionType == ActionType::SystemRestore) {
        QModelIndex currentIndex = m_treeView->currentIndex();
        currentIndex = currentIndex.sibling(currentIndex.row(), 0);
        QString choosePath = m_treeView->model()->itemData(currentIndex).values()[0].toString();
        QString backupUUID;
        if (choosePath.isEmpty()) {
            // TODO(justforlxz): 这里要更换成相应的错误，应该是ErrorType::PathError
            return onManualRestoreErrorChanged(ErrorType::MD5Error);
        }

        Q_EMIT requestManualRestore(choosePath);
        m_loadingWidget->setVisible(true);
        m_backupBtn->setVisible(false);
    }

    setFocus();
}

int doCancelRestore()
{
    QStringList args;
    args<<"/bin/deepin-recovery-tool" << "-a" << "cancel_restore";
    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 << "doCancelRestore, exitCode:" << exitCode<<", args: "<<args<<", error: "<<error;

    return exitCode;
}

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

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

    qDebug() << Q_FUNC_INFO <<", SysRestoreWidgetV20::doSuccess reboot now";
    Utils::reboot(true, false);
}

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

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

void SysRestoreWidgetV20::cancelRestoreSuccess()
{
    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 SysRestoreWidgetV20::setEnableInHighSysLevelMode(bool enable)
{
    if (nullptr != m_backupBtn) {
        m_backupBtn->setEnabled(enable);
    }

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

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

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