/*
 * Copyright (C) 2022, KylinSoft Co., Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

#include "wifi-shortcut.h"

#include <QDebug>
#include <QProcess>
#include <QDBusReply>
#include <QDBusMessage>
#include <QDBusConnection>
#include <QApplication>
#include <QTranslator>

using namespace UkuiShortcut;

UkuiShortcut::WiFiShortcut::WiFiShortcut(QObject *parent) : Shortcut(parent)
{
    m_currentStatus.setName(tr("Network"));
    m_currentStatus.setIcon(KYLIN_WIFI_PATH);
    m_currentStatus.setToolTip(tr("Network"));
    m_currentStatus.setWidgetId("org.ukui.shortcut.network");

    initMetaData();
    initQueryThread();
}

WiFiShortcut::~WiFiShortcut()
{
    endQueryThread();
    endNetworkDbus();
}

void WiFiShortcut::initQueryThread()
{
    m_wifiDbusThread = new QThread();
    m_wifiDbusQuery = new WifiDbusQuery();
    m_wifiDbusThread->start();
    m_wifiDbusQuery->moveToThread(m_wifiDbusThread);

    connect(this, &WiFiShortcut::toQueryDevice, m_wifiDbusQuery, &WifiDbusQuery::isWirelessDeviceEnabled);
    connect(m_wifiDbusQuery, &WifiDbusQuery::deviceQuery, this, &WiFiShortcut::handleDeviceQuery);

    QDBusConnection::systemBus().connect(NETWORK_MANAGER_NAME,
                                         NETWORK_MANAGER_PATH,
                                         NETWORK_MANAGER_INTERFACE,
                                         "DeviceAdded", this, SLOT(onDevicestatusChanged()));

    QDBusConnection::systemBus().connect(NETWORK_MANAGER_NAME,
                                         NETWORK_MANAGER_PATH,
                                         NETWORK_MANAGER_INTERFACE,
                                         "DeviceRemoved", this, SLOT(onDevicestatusChanged()));

    Q_EMIT toQueryDevice();
}

void WiFiShortcut::initNetworkDbus()
{
    m_networkDbusInterface = new QDBusInterface( NETWORK_MANAGER_NAME,
                                                 NETWORK_MANAGER_PATH,
                                                 NETWORK_DBUS_PROPERTIES_INTERFACE,
                                                 QDBusConnection::systemBus());
    if(m_networkDbusInterface == nullptr) {
        qWarning()<< "m_netWorkDbusInterface init error";
    }

    getUsedWIFIConnections();
}

//信号连接
void WiFiShortcut::initConnect()
{
    connect(this, &WiFiShortcut::toQueryUsedWifiConnect, m_wifiDbusQuery, &WifiDbusQuery::queryUsedWifiConnect);
    connect(m_wifiDbusQuery, &WifiDbusQuery::usedWifiName, this, &WiFiShortcut::handleUsedWifiConnect);
    connect(m_wifiDbusQuery, &WifiDbusQuery::updateState, this, &WiFiShortcut::getUsedWIFIConnections);

    initNetworkDbus();

    QDBusConnection::systemBus().connect(NETWORK_MANAGER_NAME,
                                         NETWORK_MANAGER_PATH,
                                         NETWORK_DBUS_PROPERTIES_INTERFACE,
                                         "PropertiesChanged", this, SLOT(onPropertiesChanged(QString, QVariantMap)));
}

void WiFiShortcut::endQueryThread()
{
    if (m_wifiDbusQuery) {
        disconnect(this, &WiFiShortcut::toQueryDevice, m_wifiDbusQuery, &WifiDbusQuery::isWirelessDeviceEnabled);
        disconnect(m_wifiDbusQuery, &WifiDbusQuery::deviceQuery, this, &WiFiShortcut::handleDeviceQuery);
        disconnect(this, &WiFiShortcut::toQueryUsedWifiConnect, m_wifiDbusQuery, &WifiDbusQuery::queryUsedWifiConnect);
        disconnect(m_wifiDbusQuery, &WifiDbusQuery::usedWifiName, this, &WiFiShortcut::handleUsedWifiConnect);
        disconnect(m_wifiDbusQuery, &WifiDbusQuery::updateState, this, &WiFiShortcut::getUsedWIFIConnections);
    }

    if (m_wifiDbusThread) {
        m_wifiDbusThread->quit();
        m_wifiDbusThread->wait();
        delete m_wifiDbusThread;
        m_wifiDbusThread = nullptr;
    }

    if (m_wifiDbusQuery) {
        delete m_wifiDbusQuery;
        m_wifiDbusQuery = nullptr;
    }
}

void WiFiShortcut::endNetworkDbus()
{
    if (m_networkDbusInterface) {
        delete m_networkDbusInterface;
        m_networkDbusInterface = nullptr;
    }
}

void WiFiShortcut::endConnect()
{
    if (m_wifiDbusQuery) {
        disconnect(this, &WiFiShortcut::toQueryUsedWifiConnect, m_wifiDbusQuery, &WifiDbusQuery::queryUsedWifiConnect);
        disconnect(m_wifiDbusQuery, &WifiDbusQuery::usedWifiName, this, &WiFiShortcut::handleUsedWifiConnect);
        disconnect(m_wifiDbusQuery, &WifiDbusQuery::updateState, this, &WiFiShortcut::getUsedWIFIConnections);
    }

    endNetworkDbus();

    QDBusConnection::systemBus().disconnect(NETWORK_MANAGER_NAME,
                                            NETWORK_MANAGER_PATH,
                                            NETWORK_DBUS_PROPERTIES_INTERFACE,
                                            "PropertiesChanged", this, SLOT(onPropertiesChanged(QString, QVariantMap)));
}

void WiFiShortcut::getUsedWIFIConnections()
{
    Q_EMIT toQueryUsedWifiConnect(m_networkDbusInterface);
}

void WiFiShortcut::updateIcon(QString wifiName)
{
    if (wifiName.isEmpty()) {
        if (m_wifiButtonIsOpen == true) {
            m_currentStatus.setStatusName(tr("Not connected"));
            m_currentStatus.setColor(Color::ColorRole::HighLight);
        } else {
            m_currentStatus.setStatusName(tr("Closed"));
            m_currentStatus.setColor(Color::ColorRole::BaseColor);
        }
    } else {
        m_currentStatus.setStatusName(wifiName);
        m_currentStatus.setColor(Color::ColorRole::HighLight);
    }
    emit statusChanged(m_currentStatus);
}

//启动失败使用命令行启动
bool WiFiShortcut::launchAppWithArguments(const QString& desktopFile,const QStringList& args)
{
    QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME, KYLIN_APP_MANAGER_PATH, KYLIN_APP_MANAGER_INTERFACE, "LaunchAppWithArguments");
    message << desktopFile << args;
    return QDBusReply<bool>(QDBusConnection::sessionBus().call(message)).value();
}

void WiFiShortcut::kyWifiButtonActive()
{
    QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_NETWORK_NAME, KYLIN_NETWORK_PATH,
                                                          KYLIN_NETWORK_INTERFACE, "setWirelessSwitchEnable");

    message << !m_wifiButtonIsOpen;
    QDBusConnection::sessionBus().call(message);
}

//启动网络界面
void WiFiShortcut::kywifibegin()
{
    QDBusInterface kylinNM(KYLIN_NETWORK_NAME, KYLIN_NETWORK_PATH, KYLIN_NETWORK_INTERFACE);
    kylinNM.asyncCall(QStringLiteral("showKylinNM"), static_cast<qint32>(1));
//    QStringList args;
//    args.append("--sw");
//    if(!launchAppWithArguments("/etc/xdg/autostart/kylin-nm.desktop", args)) {
//        QProcess::startDetached("kylin-nm", args);
//    }
}

QString WiFiShortcut::pluginId()
{
    return QLatin1String("WiFi");
}

//事件处理
void WiFiShortcut::active(PluginMetaType::Action action)
{
    switch (action) {
    default:
    case PluginMetaType::Action::Click:
        //qDebug() << "点击事件";
        kyWifiButtonActive();
        break;
    case PluginMetaType::Action::LongClick:
        //qDebug() << "长按事件";
        break;
    case PluginMetaType::Action::MenuRequest:
        //qDebug() << "菜单事件";
        kywifibegin();
        break;
    }
}

const StatusInfo WiFiShortcut::currentStatus()
{
    return m_currentStatus;
}

//判断无线网卡是否可用
bool WiFiShortcut::isEnable()
{
    return m_wirelessDeviceIsEnable;
}

void WiFiShortcut::setAddedState(bool added)
{
    if (m_isAdded == added) return;
    m_isAdded = added;

    if (m_isAdded) {
        initConnect();
        getButtonState();
    } else {
        endConnect();
        m_currentStatus.setColor(Color::ColorRole::BaseColor);
        m_currentStatus.setStatusName(tr("Closed"));
        Q_EMIT statusChanged(m_currentStatus);
    }
}

//网络连接状态改变
void WiFiShortcut::onPropertiesChanged(const QString &propertyType, const QVariantMap &propertyContent)
{
    if (propertyType == "org.freedesktop.NetworkManager") {
        for (const QString &keyStr : propertyContent.keys()) {
            if (keyStr == "WirelessEnabled") {
                m_wifiButtonIsOpen = propertyContent.value("WirelessEnabled").toBool();
                updateIcon("");
                continue;
//                qWarning()<<m_wifiButtonIsOpen;
            }
            //有关已连接网络变化的信号
            if ( (keyStr == "ActiveConnections") || (keyStr == "ActivatingConnection")){
                getUsedWIFIConnections();
                continue;
            }
            if (keyStr == "State"){
                int state = propertyContent.value("State").toInt();
                if (state >= 50 && state <= 70) {
                    getUsedWIFIConnections();
                }
            }
        }
    }
}

//网卡状态改变
void WiFiShortcut::onDevicestatusChanged()
{
    Q_EMIT toQueryDevice();
}

void WiFiShortcut::handleDeviceQuery(bool isUsed)
{
    m_wirelessDeviceIsEnable = isUsed;
    Q_EMIT enableStatusChanged(m_wirelessDeviceIsEnable);
}

void WiFiShortcut::handleUsedWifiConnect(QString wifiName)
{
    updateIcon(wifiName);
}

void WiFiShortcut::getButtonState()
{
    QDBusInterface interface( NETWORK_MANAGER_NAME,
                              NETWORK_MANAGER_PATH,
                              "org.freedesktop.DBus.Properties",
                              QDBusConnection::systemBus() );

    if (interface.isValid()) {
        QDBusReply<QVariant> replyEnabled = interface.call("Get", "org.freedesktop.NetworkManager", "WirelessEnabled");
        if (replyEnabled.isValid()) {
            m_wifiButtonIsOpen = replyEnabled.value().toBool();
        }
    }
}

QMap<PluginMetaType::SystemMode, PluginMetaData> WiFiShortcut::pluginMetaData()
{
    return m_metaData;
}

void WiFiShortcut::initMetaData()
{
    PluginMetaData pc {true, 0, PluginMetaType::PluginType::MenuButton};
    PluginMetaData tablet {true, 0, PluginMetaType::PluginType::MenuButton};
    m_metaData.insert(PluginMetaType::SystemMode::PC, pc);
    m_metaData.insert(PluginMetaType::SystemMode::Tablet, tablet);
}

WiFiShortcutPlugin::WiFiShortcutPlugin(QObject *parent) : UkuiShortcutPlugin(parent)
{

}

QStringList WiFiShortcutPlugin::translations()
{
    return {QStringLiteral("wifi-shortcut")};
}

Shortcut *WiFiShortcutPlugin::createShortcut()
{
    return new WiFiShortcut;
}
