#include "startuptools.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QFileInfoList>
#include <QRegularExpression>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonValue>
#include <stdlib.h>
#include <unistd.h>

const QString CONFIGPATH = "/.config/kylin-aiassistant/applist.ini";
const QString KEYWORD = "keyword";
const QString VALUEWORD = "path";
const QString BREAKSEP = ";";
const QString EXIT_KEY1 = "关闭";
const QString EXIT_KEY2 = "退出";

QSet<QString> StartUpTools::s_brightnessUpSet = StartUpTools::initConfigBrightnessUpSet();
QSet<QString> StartUpTools::s_brightnessDownSet = StartUpTools::initConfigBrightnessDownSet();
QMap<QString, QString> StartUpTools::s_playMap = StartUpTools::initConfigPlayMap();
QMap<QString, QString> StartUpTools::s_nmMap = StartUpTools::initConfigNmMap();
QMap<QString, QString> StartUpTools::s_nomalMap = QMap<QString, QString>();
//QMap<QString, QString> StartUpTools::s_tabletMap = StartUpTools::initConfigTabletMap();
//QMap<QString, QString> StartUpTools::s_exitMap = StartUpTools::initConfigExitMap();
QStringList StartUpTools::m_fullFillPathList = QStringList();
QStringList StartUpTools::m_androidDesktopfnList = QStringList();

StartUpTools *StartUpTools::getInstance()
{
    static StartUpTools instance;
    return &instance;
}

QSet<QString> StartUpTools::initConfigBrightnessUpSet()
{
    QSet<QString> set;
    set << "调高亮度"
        << "增加亮度"
        << "调高屏幕亮度"
        << "增加屏幕亮度";
    return set;
}

QSet<QString> StartUpTools::initConfigBrightnessDownSet()
{
    QSet<QString> set;
    set << "降低亮度"
        << "调低亮度"
        << "减小亮度"
        << "降低屏幕亮度"
        << "调低屏幕亮度"
        << "减小屏幕亮度";
    return set;
}

QMap<QString, QString> StartUpTools::initConfigPlayMap()
{
    QMap<QString, QString> map;
    map.insert("下一首", "next");
    map.insert("上一首", "previous");
    map.insert("播放音乐", "play");
    map.insert("暂停播放", "pause");
    map.insert("停止播放", "stop");
    map.insert("继续播放", "playPause");
    map.insert("快进", "seek:10000000");
    map.insert("后退", "seek:-10000000");
    map.insert("播放速度零点五", "setRate:0.5");
    map.insert("播放速度一点零", "setRate:1.0");
    map.insert("播放速度一点五", "setRate:1.5");
    map.insert("播放速度二点零", "setRate:2.0");

    return map;
}

QMap<QString, QString> StartUpTools::initConfigNmMap()
{
    QMap<QString, QString> map;
    map.insert("打开无线", "nmcli radio wifi on");
    map.insert("启动无线", "nmcli radio wifi on");
    map.insert("打开WIFI", "nmcli radio wifi on");
    map.insert("启动WIFI", "nmcli radio wifi on");
    map.insert("打开无线网络", "nmcli radio wifi on");
    map.insert("启动无线网络", "nmcli radio wifi on");
    map.insert("关闭无线", "nmcli radio wifi off");
    map.insert("关闭WIFI", "nmcli radio wifi off");
    map.insert("关闭无线网络", "nmcli radio wifi off");

    map.insert("打开网络", "nmcli networking on");
    map.insert("启动网络", "nmcli networking on");
    map.insert("关闭网络", "nmcli networking off");

    return map;
}

QMap<QString, QString> StartUpTools::initConfigNomalMap()
{
    QMap<QString, QString> map;
    QString confFile = QDir::homePath() + CONFIGPATH;
    QSettings settings(confFile, QSettings::IniFormat);
    settings.setIniCodec("utf8");
    int count = settings.beginReadArray("Applications");
    if (count > 0) {
        for (int i = 0; i < count; ++i) {
            settings.setArrayIndex(i);
            QString appName = settings.value("AppName").toString();
            QString appExec = settings.value("AppExec").toString();

            if (appExec.contains("\""))  // 去除引号
                appExec.remove("\"");
            if (appExec.contains("/")) { // 从exe名开始位置提取
                int startIndex = appExec.lastIndexOf("/") + 1;
                appExec = appExec.mid(startIndex);
            }
            // 排除 " " 及其后面的内容，比如 %U %F -A gui -d 400 -style=gtk2 --no-sandbox --unity-launch等
            appExec = appExec.split(" ").first();
            // 排除 "." 及其后面的内容，比如.sh
            appExec = appExec.split(".").first();

            map.insert(appName, appExec);
        }
        settings.endArray();
    } else {
        settings.endArray();
    }
    if (map.isEmpty()) {
        qWarning() << "There are no awakening keywords currently!";
    }
    return map;
}

void StartUpTools::initConfig()
{
    QString confFile = QDir::homePath() + CONFIGPATH;
    m_settingsIni = new QSettings(confFile, QSettings::IniFormat);
    m_settingsIni->setIniCodec("utf8");
    m_settingsIni->beginWriteArray("Applications");
    getDesktopFilePath();
    for (int i = 0; i < m_fullFillPathList.count(); ++i) {
        m_settingsIni->setArrayIndex(i);
        QString filePathStr = m_fullFillPathList.at(i);
        QByteArray fpbyte = filePathStr.toLocal8Bit();
        char *filepath = fpbyte.data();
        /* 通过glib库函数获取Name字段，防止特殊情况（含有字段X-Ubuntu-Gettext-Domain） */
        GKeyFile *keyfile = g_key_file_new();
        if (!g_key_file_load_from_file(keyfile, filepath, G_KEY_FILE_NONE, NULL)) {
            g_key_file_free(keyfile);
            return;
        }
        QString name = g_key_file_get_locale_string(keyfile, G_KEY_FILE_DESKTOP_GROUP,
                                                    G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
        QString exec = g_key_file_get_locale_string(keyfile, G_KEY_FILE_DESKTOP_GROUP,
                                                    G_KEY_FILE_DESKTOP_KEY_EXEC, NULL, NULL);
        g_key_file_free(keyfile);

        m_settingsIni->setValue("AppName", name);
        m_settingsIni->setValue("AppExec", exec);
    }
    m_settingsIni->endArray();

    s_nomalMap = initConfigNomalMap();
}

bool StartUpTools::inspectCtrl(const QString &key)
{
    if (s_brightnessUpSet.contains(key)) {
        m_ctrl->setBrightness(true);
        return true;
    }
    if (s_brightnessDownSet.contains(key)) {
        m_ctrl->setBrightness(false);
        return true;
    }
    if (s_playMap.contains(key)) {
        QString funcName = s_playMap.find(key).value();
        if (!funcName.isEmpty()) {
            m_ctrl->controlMprisPlayerDbus(funcName);
            return true;
        }
    }
    if (key == QString("打开蓝牙")) {
        m_ctrl->setDefaultAdapterSwitchStatus(true);
        return true;
    }
    if (key == QString("关闭蓝牙")) {
        m_ctrl->setDefaultAdapterSwitchStatus(false);
        return true;
    }
    return false;
}

QString StartUpTools::findNmKey(const QString &key)
{
    if (!s_nmMap.contains(key)) {
        return QString("");
    }
    QString path = s_nmMap.find(key).value();

    return path;
}

opType StartUpTools::isExit(const QString &key)
{
    if (key.startsWith(EXIT_KEY1) || key.startsWith(EXIT_KEY2)) {
        return CLOSE;
    }
    else if(key.startsWith("打开") || key.startsWith("启动") || key.startsWith("唤醒") || key.startsWith("开启"))
        return OPEN;
    else
        return ORTHER;
}

QString StartUpTools::findKey(const QString &key)
{
    if (!s_nomalMap.contains(key)) {
        return QString("");
    }
    QString path = s_nomalMap.find(key).value();

//    QFileInfo file;
    QString filePath = path;
    if (path.contains(" ")) {
        filePath = path.mid(0, path.indexOf(" "));
    }
//    if (!file.exists(filePath)) {
//        return QString("");
//    }

    return path;
}

void StartUpTools::startUp(const QString &path)
{
    qInfo() << "Start pulling up the app";
    QString command = path + " &";
    system(command.toStdString().c_str());
}

void StartUpTools::killProcess(const QString key)
{
    QString cmd = QString("ps -aux | grep ") + key;
    FILE *fp = popen(cmd.toStdString().c_str(), "r");
    if (fp == NULL) {
        qWarning("command fail !");
        return;
    }

    char buf[1024];
    memset(buf, '\0', sizeof(buf));
    while (!feof(fp)) {
        fgets(buf, sizeof(buf), fp);
        QString item(buf);
        memset(buf, '\0', sizeof(buf));

        if (item.isEmpty()) {
            continue;
        }

        if (item.contains("grep")) {
            continue;
        }

        if (item.contains("peony-qt-desktop")) {
            continue;
        }

        QStringList itemList = item.trimmed().split(' ');
        itemList.removeAll("");
        QString info = itemList.value(1);
        bool ok = true;
        info.toLongLong(&ok);
        if (ok) {
            QString common = QString("kill -9 ") + info;
            system(common.toStdString().c_str());
        }
    }

    pclose(fp);
}

//获取系统所有desktop文件路径
QStringList StartUpTools::getDesktopFilePath()
{
    m_fullFillPathList.clear();
    getAndroidApp();
    recursiveSearchFile("/usr/share/applications/");
    recursiveSearchFile("/var/lib/snapd/desktop/applications/");
    recursiveSearchFile("/var/lib/flatpak/exports/share/applications/");

    m_fullFillPathList.removeAll("/usr/share/applications/software-properties-livepatch.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/mate-color-select.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/blueman-adapters.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/mate-user-guide.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/nm-connection-editor.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/debian-uxterm.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/debian-xterm.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/im-config.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/fcitx.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/fcitx-configtool.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/onboard-settings.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/info.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/ukui-power-preferences.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/ukui-power-statistics.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/software-properties-drivers.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/software-properties-gtk.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/gnome-session-properties.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/org.gnome.font-viewer.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/xdiagnose.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/gnome-language-selector.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/mate-notification-properties.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/transmission-gtk.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/mpv.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/system-config-printer.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/org.gnome.DejaDup.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/yelp.desktop");
    //v10
    m_fullFillPathList.removeAll("/usr/share/applications/mate-about.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/time.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/network.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/shares.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/mate-power-statistics.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/display-im6.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/display-im6.q16.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/openjdk-8-policytool.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/kylin-io-monitor.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/wps-office-uninstall.desktop");
    m_fullFillPathList.removeAll("/usr/share/applications/wps-office-misc.desktop");
//    m_filePathList.removeAll("/usr/share/applications/kylin-installer.desktop");

    QStringList desktopList;

    for (int i = 0; i < m_fullFillPathList.count(); ++i) {
        QString filepath = m_fullFillPathList.at(i);
        int list_index = filepath.lastIndexOf('/');
        QString desktopName = filepath.right(filepath.length() - list_index - 1);

        if (desktopList.contains(desktopName)) {
            m_fullFillPathList.removeAll(filepath);
            i--;
        } else {
            desktopList.append(desktopName);
        }
    }

    return m_fullFillPathList;
}

QStringList StartUpTools::getFullDesktopFileList()
{
    return m_fullFillPathList;
}

void StartUpTools::getAndroidApp()
{
    m_androidDesktopfnList.clear();
    QVector<QStringList> androidVector;
    androidVector.clear();
    QString path = QDir::homePath() + "/.local/share/applications/";
    QDir dir(path);

    if (!dir.exists()) {
        return;
    }

    dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::DirsFirst);
    QFileInfoList list = dir.entryInfoList();

    if (list.size() < 1) {
        return;
    }

    int i = 0;
    GError **error = nullptr;
    GKeyFileFlags flags = G_KEY_FILE_NONE;
    GKeyFile *keyfile = g_key_file_new();

    do {
        QFileInfo fileInfo = list.at(i);

        if (!fileInfo.isFile()) {
            i++;
            continue;
        }

        //过滤后缀不是.desktop的文件
        QString filePathStr = fileInfo.filePath();

        if (!filePathStr.endsWith(".desktop")) {
            i++;
            continue;
        }

        QByteArray fpbyte = filePathStr.toLocal8Bit();
        char *filepath = fpbyte.data();

        if (0 != access(filepath, R_OK)) { //判断文件是否可读
            i++;
            continue;
        }

        m_keyfile = g_key_file_new();

        if (!g_key_file_load_from_file(m_keyfile, filepath, m_flags, m_error)) {
            return;
        }

        char *ret_1 = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "NoDisplay", nullptr, nullptr);

        if (ret_1 != nullptr) {
            QString str = QString::fromLocal8Bit(ret_1);
            g_free(ret_1);
            if (str.contains("true")) {
                g_key_file_free(m_keyfile);
                i++;
                continue;
            }
        }

        char *ret_2 = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "NotShowIn", nullptr, nullptr);

        if (ret_2 != nullptr) {
            QString str = QString::fromLocal8Bit(ret_2);
            g_free(ret_2);
            if (str.contains("UKUI")) {
                g_key_file_free(m_keyfile);
                i++;
                continue;
            }
        }

        //过滤LXQt、KDE
        char *ret = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "OnlyShowIn", nullptr, nullptr);

        if (ret != nullptr) {
            QString str = QString::fromLocal8Bit(ret);
            g_free(ret);
            if (str.contains("LXQt") || str.contains("KDE")) {
                g_key_file_free(m_keyfile);
                i++;
                continue;
            }
        }
        g_key_file_free(m_keyfile);
        m_fullFillPathList.append(filePathStr);
        m_androidDesktopfnList.append(fileInfo.fileName());
        i++;
    } while (i < list.size());

    g_key_file_free(keyfile);
}

//文件递归查询
void StartUpTools::recursiveSearchFile(const QString &_filePath)
{
    QDir dir(_filePath);

    if (!dir.exists()) {
        return;
    }

    dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
    dir.setSorting(QDir::DirsFirst);
    QFileInfoList list = dir.entryInfoList();
    list.removeAll(QFileInfo("/usr/share/applications/screensavers"));

    if (list.size() < 1) {
        return;
    }

    int i = 0;

    //递归算法的核心部分
    do {
        QFileInfo fileInfo = list.at(i);
        //如果是文件夹，递归
        bool isDir = fileInfo.isDir();

        if (isDir) {
            recursiveSearchFile(fileInfo.filePath());
        } else {
            //过滤后缀不是.desktop的文件
            QString filePathStr = fileInfo.filePath();

            if (!filePathStr.endsWith(".desktop")) {
                i++;
                continue;
            }

            QByteArray fpbyte = filePathStr.toLocal8Bit();
            char *filepath = fpbyte.data();

            if (0 != access(filepath, R_OK)) { //判断文件是否可读
                i++;
                continue;
            }

            m_keyfile = g_key_file_new();

            if (!g_key_file_load_from_file(m_keyfile, filepath, m_flags, m_error)) {
                g_key_file_free(m_keyfile);
                i++;
                continue;
            }

            char *ret_0 = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "Categories", nullptr, nullptr);

            if (ret_0 != nullptr) {
                QString str = QString::fromLocal8Bit(ret_0);
                g_free(ret_0);
                if (str.contains("Android")) {
                    g_key_file_free(m_keyfile);
                    i++;
                    continue;
                }
            }

            char *ret_1 = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "NoDisplay", nullptr, nullptr);

            if (ret_1 != nullptr) {
                QString str = QString::fromLocal8Bit(ret_1);
                g_free(ret_1);
                if (str.contains("true")) {
                    g_key_file_free(m_keyfile);
                    i++;
                    continue;
                }
            }

            char *ret_2 = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "NotShowIn", nullptr, nullptr);

            if (ret_2 != nullptr) {
                QString str = QString::fromLocal8Bit(ret_2);
                g_free(ret_2);
                if (str.contains("UKUI")) {
                    g_key_file_free(m_keyfile);
                    i++;
                    continue;
                }
            }

            //过滤LXQt、KDE
            char *ret = g_key_file_get_locale_string(m_keyfile, "Desktop Entry", "OnlyShowIn", nullptr, nullptr);

            if (ret != nullptr) {
                QString str = QString::fromLocal8Bit(ret);
                g_free(ret);
                if (str.contains("LXQt") || str.contains("KDE")) {
                    g_key_file_free(m_keyfile);
                    i++;
                    continue;
                }
            }

            g_key_file_free(m_keyfile);
            m_fullFillPathList.append(filePathStr);
        }

        i++;
    } while (i < list.size());
}
