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

#include "SelectPartitionDialog.h"
#include "SelectPartitionTreeView.h"
#include "utils/Utils.h"
#include "utils/global.h"
#include <QHBoxLayout>
#include <DTitlebar>
#include <QException>
#include <QJsonArray>
#include <DBackgroundGroup>
#include <DWidget>
#include <DLabel>
#include <DFontSizeManager>
#include <QScreen>
#include <DPushButton>
#include <QThread>
#include <QDebug>

// 定义列表项的宽、高，和列数
const int FIRST_COLUMNWIDTH = 50;
const int THIRD_COLUMNWIDTH = 133;
const int FOURTH_COLUMNWIDTH = 134;
const int ROW_HEIGET = 38;
const int COLUMN_NUM = 4;

SelectPartitionDialog::SelectPartitionDialog(QWidget *parent) : DMainWindow(parent)
{
    auto titleBar = titlebar();
    setWindowFlags(windowFlags());//  & Qt::WindowMinimizeButtonHint
    titleBar->setMenuVisible(false);
    titleBar->setIcon(QIcon::fromTheme("uos-recovery"));
    auto contentLayout = new QVBoxLayout;
    contentLayout->setSpacing(10);
    contentLayout->setContentsMargins(115, 16, 115, 45);

    DLabel *label = new DLabel;
    label->setText(tr("Backup location for system backup"));
    DFontSizeManager::instance()->bind(label, DFontSizeManager::T5);
    QFont font = label->font();
    font.setWeight(QFont::Medium);
    label->setFont(font);
    label->setAlignment(Qt::AlignLeft);
    contentLayout->addWidget(label);

    m_view = new SelectPartitionTreeView(this);
    m_model = new SelectPartitionItemModel(COLUMN_NUM);
    m_view->setModel(m_model);

    contentLayout->addWidget(m_view);

    m_error = new DLabel;
    m_error->setFixedHeight(40);
    m_error->setWordWrap(true);
    m_error->setAlignment(Qt::AlignHCenter);
    contentLayout->addWidget(m_error);

    m_calculateTip = new DSpinner(this);
    m_calculateTip->setFixedSize(16, 16);
    m_calculateTip->setFocusPolicy(Qt::NoFocus);
    m_calculateTip->hide();
    m_calculateText = new QLabel;
    m_calculateText->setText(tr("Calculating space..."));
    m_calculateText->hide();
    QHBoxLayout *calculateTipLayout = new QHBoxLayout();
    calculateTipLayout->setSpacing(10);
    calculateTipLayout->setContentsMargins(0,0,0,0);
    calculateTipLayout->addStretch();
    calculateTipLayout->addWidget(m_calculateTip);
    calculateTipLayout->addWidget(m_calculateText);
    calculateTipLayout->addStretch();
    contentLayout->addLayout(calculateTipLayout);

    QWidget *contentWidget = new QWidget;
    contentWidget->setObjectName("contentWidget");
    contentWidget->setLayout(contentLayout);

    auto mainLayout = new QHBoxLayout;
    auto mainWidget = new DBackgroundGroup();
    mainWidget->setObjectName("mainWidget");
    mainLayout->addWidget(contentWidget);
    setCentralWidget(mainWidget);
    centralWidget()->setLayout(mainLayout);

    // 禁止拖动列宽
    QHeaderView * headerView = m_view->header();
    headerView->setSectionResizeMode(0, QHeaderView::ResizeMode::Fixed);
    headerView->setSectionResizeMode(1, QHeaderView::ResizeMode::Fixed);
    headerView->setSectionResizeMode(2, QHeaderView::ResizeMode::Fixed);
    headerView->setSectionResizeMode(3, QHeaderView::ResizeMode::Fixed);

    connect(m_view, &SelectPartitionTreeView::clicked, this, &SelectPartitionDialog::onSelectPartitionTreeViewClicked);
}

void SelectPartitionDialog::setData(QString &jsonString, const QString &currUUID)
{
    try {
        m_partInfoMap.clear();
        m_model->setHeadData({"", tr("Partition"), tr("Capacity"), tr("Free Space")});

        QJsonObject jsonRoot = Utils::QStringToJson(jsonString);
        QJsonArray disks = jsonRoot.value("disks").toArray();

        for (int i = 0; i < disks.size(); ++i) {
            QJsonObject diskObject = disks.at(i).toObject();
            QString devSize = Utils::byte2DisplaySize(diskObject.value("size").toVariant().toULongLong());
            QString deviceName;
            if (diskObject.contains("vg")) {
                deviceName = diskObject.value("vg").toString() + " " + devSize;
            } else if (diskObject.contains("disk")) {
                deviceName = diskObject.value("disk").toString() + " " + devSize;
            }
            QList<QJsonObject> partInfoData;
            QJsonArray partitions = diskObject.value("partitions").toArray();
            for (int j = 0; j < partitions.size(); ++j) {
                QJsonObject partitionObject = partitions.at(j).toObject();
                Partition partition;
                partition.unmarshal(partitionObject);
                if (partition.externalDevice) {
                    continue;
                }
                partInfoData.append(partitionObject);
            }
            if (!partInfoData.isEmpty()) {
                m_partInfoMap.insert(deviceName, partInfoData);
            }
        }
        m_model->setDatas(m_partInfoMap);

        QList<SelectPartitionModelItem> dataInfoList = m_model->getDataInfos();
        for (int i = 0; i < dataInfoList.size(); i++) {
            if (!dataInfoList.at(i).uuid.compare(currUUID)) {
                m_view->setSelectIndex(i);
                m_lastPartionRowIndex = i;
                m_sucessPartionRowIndex = i;
                break;
            }
        }

    } catch (QException &e) {
        qCritical() << "json parse failed:" << e.what();
        return;
    }
}

void SelectPartitionDialog::showToCenter()
{
    auto screen = QGuiApplication::primaryScreen();
    auto rect = screen->geometry();
    if (rect.width() < MAIN_WINDOW_WIDTH || rect.height() < MAIN_WINDOW_HEIGHT) {
        QWidget::showMaximized();
    } else {
        setFixedSize(QSize(MAIN_WINDOW_WIDTH - 80, MAIN_WINDOW_HEIGHT - 80));
        move((rect.width() - width()) / 2, (rect.height() - height()) / 2);
        QWidget::show();
    }

    // 设置列表项的宽、高
    QList<int> columsizes = {FIRST_COLUMNWIDTH,
                             m_view->width() - FIRST_COLUMNWIDTH - THIRD_COLUMNWIDTH - FOURTH_COLUMNWIDTH,
                             THIRD_COLUMNWIDTH,
                             FOURTH_COLUMNWIDTH};
    m_view->setColumnsRowSize(columsizes, ROW_HEIGET);
}

void SelectPartitionDialog::startSpinner()
{
    m_error->setText("");
    m_error->hide();
    m_calculateText->show();
    m_calculateTip->start();
    m_calculateTip->show();
}

void SelectPartitionDialog::stopSpinner()
{
    m_calculateText->hide();
    m_calculateTip->stop();
    m_calculateTip->hide();
    m_error->show();
}

void SelectPartitionDialog::onShowResult(int errorCode)
{
    if (0 != errorCode && -1 != m_sucessPartionRowIndex) {
        m_view->setSelectIndex(m_sucessPartionRowIndex);
    }

    if (errorCode == 0) {
        m_error->setText(tr("Backup location successfully set"));
        m_error->setStyleSheet("QLabel {"
                                 "font-size: 14px;"
                                 "font-weight: Medium;"
                                 "color: green;"
                                 "}");
        if (-1 != m_curPartionRowIndex) {
            m_lastPartionRowIndex = m_curPartionRowIndex;
            m_sucessPartionRowIndex = m_curPartionRowIndex;
            m_view->setSelectIndex(m_sucessPartionRowIndex);
        }
    } else if (errorCode == static_cast<int> (ErrorCode::PartitionNotSupportRecovery)) {
        m_error->setText(tr("The file system of the partition is unsupported. Please select one in ext4, btrfs, xfs format."));
        m_error->setStyleSheet("QLabel {"
                                 "font-size: 14px;"
                                 "font-weight: Medium;"
                                 "color: #FF5736;"
                                 "}");
    }  else if (errorCode == static_cast<int> (ErrorCode::TmpPartitionNotSupport)) {
        m_error->setText(m_curPartitionName + ": " + tr("Do not select a partition with the /tmp mount point, which will erase the backup data"));
        m_error->setStyleSheet("QLabel {"
                               "font-size: 14px;"
                               "font-weight: Medium;"
                               "color: #FF5736;"
                               "}");
    } else {
        m_error->setText(m_curPartitionName + ": " + tr("Insufficient space in the selected partition"));
        m_error->setStyleSheet("QLabel {"
                                 "font-size: 14px;"
                                 "font-weight: Medium;"
                                 "color: #FF5736;"
                                 "}");
    }
    stopSpinner();
}

void SelectPartitionDialog::setErrorText(const QString &text)
{
    if (nullptr != m_error) {
        m_error->setText(text);
    }
}

void SelectPartitionDialog::setDestUUID(const QString &destUUID)
{
    m_currDestUUID = destUUID;
}

void SelectPartitionDialog::onSelectPartitionTreeViewClicked(const QModelIndex &index)
{
    SelectPartitionModelItem modeItem = m_model->getDataInfo(index.row());
    if ("root" == modeItem.itemType) {
        return;
    }
    m_curPartitionName = modeItem.name;
    if ("/tmp" == modeItem.mountPoint) {
        onShowResult(ErrorCode::TmpPartitionNotSupport);
        return;
    }

    if (modeItem.free <= static_cast<quint64>(GiB)) {
        onShowResult(ErrorCode::InsufficientDiskSpace);
        return;
    }

    m_curPartionRowIndex = index.row();
    if (modeItem.uuid == m_currDestUUID) {
        if (m_curPartionRowIndex == m_lastPartionRowIndex) {
            m_error->setText(tr(""));
        } else {
            m_lastPartionRowIndex = m_curPartionRowIndex;
            onShowResult(OK);
        }

        m_view->setSelectIndex(m_curPartionRowIndex);
        return;
    }

    QString deviceName;
    int partIndex = -1;

    if (0 != m_view->getTreeViewClickedDeviceName(index, partIndex, deviceName)) {
        return;
    }

    if (m_partInfoMap.contains(deviceName)) {
        QList<QJsonObject> parts = m_partInfoMap.value(deviceName);
        if (partIndex < parts.size()) {
            if (!m_currDestUUID.isEmpty()) {
                DDialog dialog(this);
                dialog.setMessage(tr("Note: You should perform a full backup if the storage location changes. Please delete the old backup files manually."));
                dialog.addButton(tr("Cancel", "button"));
                dialog.setIcon(QIcon::fromTheme("dialog-warning"));
                QRect rect = geometry();
                dialog.move(rect.center());
                dialog.moveToCenter();

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

            startSpinner();
            // m_lastPartionRowIndex = m_curPartionRowIndex;
            m_view->setSelectIndex(index.row());
            Q_EMIT destDeviceChange(parts.at(partIndex));
        }
    }
}

