#include "bootinterface.h"
#include <QThreadPool>
#include <QGSettings>
#include <kysdk/kysdk-system/libkysysinfo.h>

BootInterface::BootInterface():UKUI::ServiceObject(nullptr), QDBusContext()
{
    // 线程池初始化，设置最大线程池数
    m_pThread = new QThreadPool(this);
    m_pThread->setMaxThreadCount(1);
    QDBusConnection::systemBus().connect(QString(), QString("/"), "com.control.center.interface", "updateFinished", this, SLOT(taskFinishedSlot(bool)));
    QDBusInterface m_pUkccSystemDbus("com.control.center.qt.systemdbus",
                                      "/",
                                      "com.control.center.interface",
                                      QDBusConnection::systemBus(), this);

    if (!isSameSystems()) {
        QGSettings ukcc(UKCC_SCHAME);
        // 获取到当前系统不一致，设置gsetting提供给前端取消勾选
        ukcc.set(SYSTEMS_SAME, false);

        QString lang = qgetenv("LANG");
        m_pUkccSystemDbus.call("updateGrub", lang);
    }

    QDBusReply<bool> verify = m_pUkccSystemDbus.call("getGrupPasswdStatus");
    m_needVerify = verify;
    QDBusReply<int> delay = m_pUkccSystemDbus.call("getGrubBootTime");
    m_bootDelay = delay;
    QDBusReply<int> defaultorder = m_pUkccSystemDbus.call("getDefaultBootItem");
    m_grubDefault = defaultorder;
}

BootInterface::~BootInterface()
{
}

bool BootInterface::isSameSystems()
{
    // 1.获取当前/boot/grub/grub.cfg文件中启动项
    QString grubMenus(kdk_system_get_grub_menu());
    grubMenus.remove("\"");
    grubMenus.remove("{");
    grubMenus.remove("}");

    qDebug() << "get boot list = " << grubMenus;
    QStringList grubMenuItem =  grubMenus.split(",");
    int gotSystems = 0;
    // 2.windows不存在os-release，判断方式为linux判断方式，去掉列表中windows
    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);
                if (!QString(item.at(0)).contains("windows", Qt::CaseInsensitive)) {
                    gotSystems++;
                }
            }
        }
    }

    // 3.根据挂载目录/etc/os-release获取实际存在os数，windows不存在os-release
    int actualSystems = 0;
    QList<QStorageInfo> storelist = QStorageInfo::mountedVolumes();
    foreach (const QStorageInfo &storea, storelist) {
        qDebug() << "device:" << storea.device() << "path:" << storea.rootPath();
        if (storea.rootPath() == "/usr") {
            qDebug() << "filter /usr path";
            continue;
        }
        QFile file(QString(storea.rootPath()+"/etc/os-release"));
        if (file.exists()) {
            qDebug() << "found a os-release file,path is " << QString(storea.rootPath()+"/etc/os-release");
            actualSystems++;
        }
    }

    // 4.比较sdk接口获取与实际os数，更新grub
    qDebug() << "gotsystems = " << gotSystems << "actualsystems = " << actualSystems;
    if (gotSystems == actualSystems) {
        return true;
    }
    return false;
}

void BootInterface::taskFinishedSlot(bool reply)
{
    qDebug() << "task finished";
    GrubTask *task = runlist.at(0);
    int type = task->getTaskType();
    runlist.clear();

    //waitlist -> runlist;
    if (!waitlist.isEmpty()) {
        qDebug() << "add task " << waitlist.first() << "to runlist";
        runlist.append(waitlist.first());
        waitlist.pop_front();

        qDebug() << "waitlist = " << waitlist << "removed task from waitlist ";
    }

    if (!runlist.isEmpty()) {
        qDebug() << "start new task = " << runlist[0];
        m_pThread->start(runlist[0]);
    }

    if (waitlist.isEmpty() && runlist.isEmpty()) {
        // update status
        qDebug() << "The last one task has finished";
        QDBusInterface m_pUkccSystemDbus("com.control.center.qt.systemdbus",
                                          "/",
                                          "com.control.center.interface",
                                          QDBusConnection::systemBus(), this);
        QDBusReply<bool> verify = m_pUkccSystemDbus.call("getGrupPasswdStatus");
        m_needVerify = verify;
        QDBusReply<int> delay = m_pUkccSystemDbus.call("getGrubBootTime");
        m_bootDelay = delay;
        QDBusReply<int> defaultorder = m_pUkccSystemDbus.call("getDefaultBootItem");
        m_grubDefault = defaultorder;
        Q_EMIT finished(type, reply);
    }
}

bool BootInterface::callerPathCompare(QString path)
{
    QString clientService = message().service();
    QDBusConnectionInterface *intf = connection().interface();
    unsigned int  pid = intf->servicePid(clientService).value();
    /*check caller white list*/
    QFileInfo file(QString("/proc/%1/exe").arg(pid));
    QString execPath = "";
    if (file.exists()) {
        execPath= file.canonicalFilePath();
    }
    if (execPath != path) {
        return false;
    }

    return true;
}

void BootInterface::addTask(QString pwd, bool isOpen, int type)
{
    // 判断是否ukui-control-center进程调用，不对外提供
    if (!callerPathCompare("/usr/bin/ukui-control-center")){
        qDebug() << "The process has not permission to call this method";
        return;
    }

    qDebug() << "task type = " << type;
    GrubTask *task = new GrubTask(pwd, isOpen, type);
    if (runlist.isEmpty())  {
        qDebug() << "add task = " << type << " to runlist" << runlist;
        runlist.append(task);
        m_pThread->start(task);
    } else {
        waitlist.append(task);
        qDebug() << "add task = " << type << " to waitlist" << waitlist;
    }

    m_needVerify = isOpen;

//    connect(task, &GrubTask::taskFinished, this, [=](bool success){
//        qDebug() << "task = " << type << "finished,then ret =" << success;
//        Q_EMIT finished(type, success);
//    });
}

void BootInterface::addTask(int order, int type)
{
    // 判断是否ukui-control-center进程调用，不对外提供
    if (!callerPathCompare("/usr/bin/ukui-control-center")){
        qDebug() << "The process has not permission to call this method";
        return;
    }

    GrubTask *task = new GrubTask(order, type);
    if (runlist.isEmpty())  {
        runlist.append(task);
        qDebug() << "add task = " << type << " to runlist" << runlist;
        m_pThread->start(task);
    } else {
        qDebug() << "add task = " << type << " to waitlist" << waitlist;
        waitlist.append(task);
    }

    if (type == 1) {
        m_bootDelay = order;
    } else if (type == 2) {
        m_grubDefault = order;
    }

//    connect(task, &GrubTask::taskFinished, this, [=](bool success){
//        qDebug() << "task = " << type << "finished,then ret =" << success;
//        Q_EMIT finished(type, success);
//    });
}

bool BootInterface::inhibit(QString what, QString who, QString why, QString mode)
{
    QDBusMessage message;

    message = QDBusMessage::createMethodCall("org.freedesktop.login1",
                                             "/org/freedesktop/login1",
                                             "org.freedesktop.login1.Manager",
                                             QStringLiteral("Inhibit"));


    message.setArguments(QVariantList({what, who, why, mode}));

    QDBusPendingReply<QDBusUnixFileDescriptor> reply = QDBusConnection::systemBus().call(message);

    if (!reply.isValid()) {
        qCritical() << "inhibit failed!";
        return false;
    }
    reply.value().swap(m_inhibitFileDescriptor);
    qCritical() << "inhibit success!";
    return true;
}

bool BootInterface::getVerifyStatus()
{
    return m_needVerify;
}

int BootInterface::getBootDelay()
{
    return m_bootDelay;
}

int BootInterface::getGrubDefault()
{
    return m_grubDefault;
}

void BootInterface::uninhibit()
{
    if (!m_inhibitFileDescriptor.isValid()) {
        return;
    }

    qCritical() << "uninhibit success!";
    m_inhibitFileDescriptor = QDBusUnixFileDescriptor();
}

