#include "boot.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QDebug>
#include <polkit-qt5-1/polkitqt1-authority.h>
#include <kysdk/applications/accessinfohelper.h>
using namespace kdk;

#include <kysdk/kysdk-system/libkysysinfo.h>

#include "lightlabel.h"

#include "grubverifydialog.h"
#include "ukcccommon.h"
using namespace ukcc;

enum TaskType {
    GRUBVERIFY,
    BOOTDELAY,
    DEFAULTBOOT,
};

#define DEFAULTLISTHEIGHT 240
Boot::Boot() : m_firstLoad(true)
{
    m_pluginName = tr("Boot");
    m_pluginType = COMMONINFO;
}

Boot::~Boot()
{
}

QString Boot::plugini18nName()
{
    return m_pluginName;
}

int Boot::pluginTypes()
{
    return m_pluginType;
}

QWidget *Boot::pluginUi()
{
    if (m_firstLoad) {
        m_firstLoad = false;
        m_pPluginWidget = new QWidget;
        m_pPluginWidget->setAttribute(Qt::WA_DeleteOnClose);

        initUI(m_pPluginWidget);

        m_pUkccSystemDbus = new QDBusInterface("com.control.center.qt.systemdbus",
                                          "/",
                                          "com.control.center.interface",
                                          QDBusConnection::systemBus(), this);
        qCritical() << "default timeout = " << m_pUkccSystemDbus->timeout();
        m_pUkccSystemDbus->setTimeout(2147483647); // -1 为默认的25s超时;
        if (!m_pUkccSystemDbus->isValid()){
            qCritical() << "Create Client Interface Failed:" << QDBusConnection::systemBus().lastError();
        }

        m_pUkccSessionDbus = new QDBusInterface( "org.ukui.ukcc.session",
                                                "/Boot",
                                                "org.ukui.ukcc.session.Boot",
                                                QDBusConnection::sessionBus(), this);

        m_pUkccSessionDbus->setTimeout(2147483647); // -1 为默认的25s超时;
        if (!m_pUkccSessionDbus->isValid()){
            qCritical() << "Create Client Interface Failed:" << QDBusConnection::sessionBus().lastError();
        }

        m_pukccGsetting = new QGSettings(UKCC_SCHAME, QByteArray(), this);

        initConnection();
    }
    return m_pPluginWidget;
}

const QString Boot::name() const
{
    return QStringLiteral("Boot");
}

bool Boot::isShowOnHomePage() const
{
    return true;
}

QIcon Boot::icon() const
{
    return QIcon::fromTheme("ukui-bootmenu-symbolic");
}

bool Boot::isEnable() const
{
    // icbc项目要求隐藏
    QString platformName = QString(QLatin1String(kdk_system_get_appScene()));
    qDebug() << "platformName = " << platformName;
    if (platformName.contains("ICBC", Qt::CaseInsensitive)) {
        return false;
    }
    return true;
}

void Boot::initUI(QWidget *widget)
{
    QVBoxLayout *mainVLayout = new QVBoxLayout(widget);
    mainVLayout->setContentsMargins(0, 0, 0, 0);

    KLabel *bootTitleLabel = new KLabel(m_pPluginWidget);
    bootTitleLabel->setContentsMargins(16,0,0,0);
    KDK_EXTEND_ALL_INFO_FORMAT(bootTitleLabel, name(), "", "");
    //~ contents_path /Boot/Boot
    bootTitleLabel->setText(tr("Boot"));
    bootTitleLabel->setContentsMargins(14,0,0,0);

    //~ contents_path /Boot/Grub Password Verification
    m_pBootFrame = new SwitchWidget(tr("Grub Password Verification"), m_pPluginWidget, UkccFrame::BorderRadiusStyle::Around, tr("Password verification is required to edit Grub startup parameters"));
    m_pBootFrame->setMinimumSize(QSize(550, 0));
    m_pBootFrame->setMaximumSize(QSize(16777215, 16777215));
    m_pBootFrame->setHeightAdaptive(false);
    m_pResetPasswdBtn = new KPushButton();
    m_pResetPasswdBtn->setText(tr("Reset password"));
    m_pBootFrame->insertWidget(2, m_pResetPasswdBtn);
    KDK_EXTEND_ALL_INFO_FORMAT(m_pBootFrame, name(), "", "");
    KDK_EXTEND_ALL_INFO_FORMAT(m_pResetPasswdBtn, name(), "", "");
    KDK_EXTEND_ALL_INFO_FORMAT(m_pBootFrame->switchButton(), name(), "", "");

    //~ contents_path /Boot/Grub Boot Delay
    m_pGrubBootDelayFrame = new ComboxWidget(tr("Grub Boot Delay"), m_pPluginWidget, UkccFrame::Around);
    m_pGrubBootDelayFrame->label()->setFixedWidth(550);
    KDK_EXTEND_ALL_INFO_FORMAT(m_pGrubBootDelayFrame->label(), name(), "BootDelayLabel", "");
    m_pGrubBootDelayFrame->comboBox()->addItem(tr("1s"), 1);
    m_pGrubBootDelayFrame->comboBox()->addItem(tr("3s"), 3);
    m_pGrubBootDelayFrame->comboBox()->addItem(tr("5s"), 5);
    m_pGrubBootDelayFrame->comboBox()->addItem(tr("10s"), 10);
    m_pGrubBootDelayFrame->comboBox()->addItem(tr("Infinite Waiting"), -1);
    KDK_EXTEND_ALL_INFO_FORMAT(m_pGrubBootDelayFrame->comboBox(), name(), "BootDelayCombox", "");

    m_pBootOrderFrame = new KBackgroundGroup(m_pPluginWidget);
    QWidget *defaultBootwidget = new QWidget();
    m_pDefaultBootLabel = new KLabel(defaultBootwidget);
    //~ contents_path /Boot/Default Startup System
    m_pDefaultBootLabel->setText(tr("Default Startup System"));
    KDK_EXTEND_ALL_INFO_FORMAT(m_pDefaultBootLabel, name(), "BootOrderLabel", "");
    QHBoxLayout *widget1Layout = new QHBoxLayout(defaultBootwidget);
    widget1Layout->setContentsMargins(16, 0, 16, 0);
    widget1Layout->addWidget(m_pDefaultBootLabel);
    m_pBootOrderFrame->addWidget(defaultBootwidget);

    m_pBootListGroup = new QButtonGroup();

    mainVLayout->addWidget(bootTitleLabel);
    mainVLayout->addWidget(m_pBootFrame);
    mainVLayout->addWidget(m_pGrubBootDelayFrame);
    mainVLayout->addWidget(m_pBootOrderFrame);
    mainVLayout->addStretch();

    // 判断CPU架构隐藏
    QString cpu = UkccCommon::getCpuArchitecture();
    if (cpu.contains("sw") || cpu.contains("mips")) {
        m_pGrubBootDelayFrame->setVisible(false);
        m_pBootOrderFrame->setVisible(false);
    }
}

void Boot::initConnection()
{
    initGrubVerifyStatus();
    initBootTime();

    initBootList();
    initDefaultBoot();

    connect(m_pBootFrame->switchButton(), &KSwitchButton::stateChanged, this, &Boot::bootSlot);

    connect(m_pResetPasswdBtn, &QPushButton::clicked, this, &Boot::resetPasswdSlot);

    connect(m_pGrubBootDelayFrame->comboBox(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Boot::changeBootDelay);

    connect(m_pBootListGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked), this, &Boot::setDefaultBoot);

    QDBusConnection::sessionBus().connect(QString(), QString("/Boot"), "org.ukui.ukcc.session.Boot", "finished", this, SLOT(taskFinished(int,bool)));
}

bool Boot::authoriyGrub()
{
    PolkitQt1::Authority::Result result;

    result = PolkitQt1::Authority::instance()->checkAuthorizationSync(
            "org.control.center.qt.systemdbus.action.grub",
            PolkitQt1::UnixProcessSubject(QCoreApplication::applicationPid()),
            PolkitQt1::Authority::AllowUserInteraction);

    if (result == PolkitQt1::Authority::Yes){
        return true;
    } else {
        return false;
    }
}

void Boot::taskFinished(int type, bool reply)
{
    qDebug() << "setting finished: type = " << type << "reply = " << reply;
    if (m_pLoadingWidget) {
        m_pLoadingWidget->hide();
        m_pLoadingWidget->close();
    }
    QDBusReply<bool> grubVerify;
    if (!reply) {
        switch (type) {
        case GRUBVERIFY:
            grubVerify = m_pUkccSystemDbus->call("getGrupPasswdStatus");
            m_pBootFrame->switchButton()->blockSignals(true);
            m_pBootFrame->switchButton()->setChecked(grubVerify);
            m_pBootFrame->switchButton()->blockSignals(false);
            m_pResetPasswdBtn->setVisible(m_pBootFrame->switchButton()->isChecked());
            break;
        case BOOTDELAY:
            initBootTime();
            break;
        case DEFAULTBOOT:
            initDefaultBoot();
            break;
        default:
            break;
        }
    } else {
        // 设置成功默认启动项，将gsetting设置为true
        switch (type) {
        case DEFAULTBOOT:
            if (!m_pukccGsetting->get(SYSTEMS_SAME).toBool()) {
                m_pukccGsetting->set(SYSTEMS_SAME, true);
            }
            break;
        default:
            break;
        }
    }
}

void Boot::initBootList()
{
    QString grubMenus(kdk_system_get_grub_menu());
    grubMenus.remove("\"");
    grubMenus.remove("{");
    grubMenus.remove("}");

    qDebug() << "get boot list = " << grubMenus;
    QStringList grubMenuItem =  grubMenus.split(",");
    for (int i = 0; i < grubMenuItem.count(); i++) {
        QString tmp = grubMenuItem[i];
        QStringList item = tmp.split(":");
        if (item.size() >= 2) {
            qDebug() << "grub menu type :" << item.at(1);
            if (item.at(1) == "menuentry") {
                qDebug() << "grub menu :" << item.at(0);
                QWidget *widget = new QWidget();
                QRadioButton *bootItemRadioBtn = new QRadioButton();
                bootItemRadioBtn->setText(item.at(0));
                bootItemRadioBtn->setProperty("grubOrder", i);
                QHBoxLayout *widget1Layout = new QHBoxLayout(widget);
                widget1Layout->setContentsMargins(16, 0, 16, 0);
                widget1Layout->addWidget(bootItemRadioBtn);
                m_pBootOrderFrame->addWidget(widget);

                m_pBootListGroup->addButton(bootItemRadioBtn, i);
            }
        }
    }
}

void Boot::initDefaultBoot()
{
    if (m_pUkccSessionDbus != nullptr) {
//        QDBusReply<int> ret = m_pUkccSessionDbus->call("getGrubDefault");

        // 获取到当前系统不一致，启动项列表不进行勾选
        qDebug() << "gsetting key of system-same = " << m_pukccGsetting->get(SYSTEMS_SAME).toBool();
        if (!m_pukccGsetting->get(SYSTEMS_SAME).toBool()) {
            return;
        }

        QDBusReply<int> ret = m_pUkccSystemDbus->call("getDefaultBootItem");

        m_preBootDefault = ret;
        if (ret >= 0) {
            m_pBootListGroup->blockSignals(true);
            m_pBootListGroup->button(ret)->setChecked(true);
            m_pBootListGroup->blockSignals(false);
        }
    }
}

void Boot::initGrubVerifyStatus()
{
    if (m_pUkccSessionDbus != nullptr) {
//        QDBusReply<bool> ret = m_pUkccSessionDbus->call("getVerifyStatus");
        QDBusReply<bool> ret = m_pUkccSystemDbus->call("getGrupPasswdStatus");
        m_pBootFrame->switchButton()->blockSignals(true);
        m_pBootFrame->switchButton()->setChecked(ret);
        m_pBootFrame->switchButton()->blockSignals(false);
    }

    m_pResetPasswdBtn->setVisible(m_pBootFrame->switchButton()->isChecked());
}

void Boot::initBootTime()
{
    if (m_pUkccSessionDbus != nullptr) {
//        QDBusReply<int> ret = m_pUkccSessionDbus->call("getBootDelay");
        QDBusReply<int> ret = m_pUkccSystemDbus->call("getGrubBootTime");
        m_preBootDelay = ret;
        m_pGrubBootDelayFrame->comboBox()->blockSignals(true);
        switch (ret) {
        case 1:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(0);
            break;
        case 3:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(1);
            break;
        case 5:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(2);
            break;
        case 10:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(3);
            break;
        case -1:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(4);
            break;
        default:
            break;
        }
        m_pGrubBootDelayFrame->comboBox()->blockSignals(false);
    }
}

void Boot::bootSlot(bool checked)
{
    if (checked) {
        GrubVerify *dia = new GrubVerify(m_pPluginWidget);
        QPushButton *confirmBtn = dia->getConfirmBtn();
        connect(confirmBtn, &QPushButton::clicked, this, [=](){
            setGrubPasswd(dia->getPwd(),checked);
        });
        if (dia->exec() != QDialog::Accepted) {
            m_pBootFrame->switchButton()->blockSignals(true);
            m_pBootFrame->switchButton()->setChecked(!checked);
            m_pBootFrame->switchButton()->blockSignals(false);
            m_pResetPasswdBtn->setVisible(m_pBootFrame->switchButton()->isChecked());
        }
    } else {
        setGrubPasswd("", checked);
    }

    UkccCommon::buriedSettings(name(), "open grub passwd", QString("settings"), m_pBootFrame->switchButton()->isChecked() ? "true" : "false");
    m_pResetPasswdBtn->setVisible(m_pBootFrame->switchButton()->isChecked());
}

void Boot::setGrubPasswd(QString pwd, bool isOpen)
{
    if (!authoriyGrub()){
        m_pBootFrame->switchButton()->blockSignals(true);
        m_pBootFrame->switchButton()->setChecked(!isOpen);
        m_pBootFrame->switchButton()->blockSignals(false);
        return;
    }

    m_pUkccSessionDbus->call("addTask", pwd, isOpen, 0);
    showLoadingWidget(m_pBootFrame->title());
}

void Boot::resetPasswdSlot()
{
    GrubVerify *dia =  new GrubVerify(m_pPluginWidget);
    QPushButton *confirmBtn = dia->getConfirmBtn();
    connect(confirmBtn, &QPushButton::clicked, this, [=](){
        if (!authoriyGrub()){
            return;
        }

        UkccCommon::buriedSettings(name(), m_pResetPasswdBtn->text(), QString("clicked"), m_pBootFrame->title());

        showLoadingWidget(m_pBootFrame->title());
        m_pUkccSessionDbus->call("addTask", dia->getPwd(), true, 0);
    });
    dia->exec();
}

void Boot::changeBootDelay(int index)
{
    if (!authoriyGrub()){
        m_pGrubBootDelayFrame->comboBox()->blockSignals(true);
        switch (m_preBootDelay) {
        case 1:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(0);
            break;
        case 3:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(1);
            break;
        case 5:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(2);
            break;
        case 10:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(3);
            break;
        case -1:
            m_pGrubBootDelayFrame->comboBox()->setCurrentIndex(4);
            break;
        default:
            break;
        }
        m_pGrubBootDelayFrame->comboBox()->blockSignals(false);
        return;
    }

    // 启动延时 修改/etc/default/grub中GRUB_TIMEOUT,update-grub
    qDebug() << "set boot delay = " << m_pGrubBootDelayFrame->comboBox()->currentData().toInt();
    m_preBootDelay = m_pGrubBootDelayFrame->comboBox()->currentData().toInt();

    UkccCommon::buriedSettings(name(), m_pGrubBootDelayFrame->title(), QString("selected"), QString::number(m_pGrubBootDelayFrame->comboBox()->currentData().toInt()));

    m_pUkccSessionDbus->call("addTask", m_pGrubBootDelayFrame->comboBox()->currentData().toInt(), 1);
    showLoadingWidget(m_pGrubBootDelayFrame->title());
}

void Boot::setDefaultBoot(QAbstractButton *button)
{
    int order = button->property("grubOrder").toInt();

    // 获取到当前系统一致，设置默认启动项时不弹授权
    if (m_pukccGsetting->get(SYSTEMS_SAME).toBool()) {
        // 获取到当前系统一致并点击启动项为当前启动项，不弹授权
        QDBusReply<int> ret = m_pUkccSystemDbus->call("getDefaultBootItem");
        if (ret == order) {
            return;
        }
    }

    if (!authoriyGrub()){
        m_pBootListGroup->blockSignals(true);
        m_pBootListGroup->button(m_preBootDefault)->setChecked(true);
        m_pBootListGroup->blockSignals(false);
        return;
    }

    qDebug() << "set default boot = " << order << button->text();
    m_preBootDefault = order;

    UkccCommon::buriedSettings(name(), m_pDefaultBootLabel->text(), QString("selected"), button->text());

    showLoadingWidget(m_pDefaultBootLabel->text());
    m_pUkccSessionDbus->call("addTask", order, 2);
}

void Boot::showLoadingWidget(QString text)
{
    if (m_pLoadingWidget == nullptr) {
        QWidget *parentWidget = m_pPluginWidget->topLevelWidget();
        m_pLoadingWidget = new LoadingWidget(parentWidget, 0.4);
        m_pLoadingWidget->setGeometry(0, 0, parentWidget->geometry().width(), parentWidget->geometry().height());
    }

    m_pLoadingWidget->setLoadingText(text);
    m_pLoadingWidget->setLoading();
    m_pLoadingWidget->show();

}
