/*
 * Copyright (C) 2023, 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 "upm_daemon.h"

static QStringList g_policyList = {"performance", "balance", "powersave"};

UpmDaemon::UpmDaemon(QObject *parent) : QObject(parent)
{
    UpmCustomDefaultGsettings upmCustomDefaultGsettings;
    upmCustomDefaultGsettings.setUpmCustomDefaultGsettings();

    QStringList valueRange = {QString::number(0), QString::number(3)};
    m_powerPolicyAc = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_POWER_POLICY_AC,
                power_policy_performance, QVariant::Int,
                valueRange, true).toInt();

    if (true == UpmUpowerDBus::self()->getAcOnlineState()) {
        UpmControlDBus::self()->controlPowerManagement(
                    UPM_DBUS_METHOD_SET_PC_POLICY, m_powerPolicyAc);
    }
    connect(UpmGsettings::self(), &UpmGsettings::powerPolicyAcChanged,
            this, &UpmDaemon::dealPowerPolicyAcChanged);

    m_brightness = new UpmBrightness(this);

    if (false == UpmCommonDBus::self()->isCloudPlatform()) {
        m_systemIdle = new UpmSystemIdle(this);
    }

    m_fractionalFreezing = new UpmFractionalFreezing(this);

    if (true == UpmUpowerDBus::self()->hasBattery()) {
        m_powerPolicyBattery = UpmCheckConfig::checkConfig(
                    GSETTINGS_KEY_POWER_POLICY_BATTERY,
                    power_policy_performance, QVariant::Int,
                    valueRange, true).toInt();
        if (false == UpmUpowerDBus::self()->getAcOnlineState()) {
            UpmControlDBus::self()->controlPowerManagement(
                        UPM_DBUS_METHOD_SET_PC_POLICY, m_powerPolicyBattery);
        }
        connect(UpmGsettings::self(), &UpmGsettings::powerPolicyBatteryChanged,
                this, &UpmDaemon::dealPowerPolicyBatteryChanged);

        m_powerPolicyBatteryBackup = UpmCheckConfig::checkConfig(
                    GSETTINGS_KEY_POWER_POLICY_BATTERY_BACKUP,
                    power_policy_unknown, QVariant::Int,
                    valueRange, true).toInt();

        connect(UpmGsettings::self(), &UpmGsettings::powerPolicyBatteryBackupChanged,
                this, &UpmDaemon::dealPowerPolicyBatteryBackupChanged);

        m_powerChanged = new UpmPowerChanged(this);

        m_lid = new UpmLid(this);

        m_lowPower = new UpmLowPower(this);

        connect(m_lowPower, &UpmLowPower::percentageLowSignal,
                m_fractionalFreezing, &UpmFractionalFreezing::dealBatteryLowState);
    }

    connect(UpmControlDBus::self(), &UpmControlDBus::systemConfigChangedSignal,
            this, &UpmDaemon::dealSystemConfigChanged);
    connect(UpmCommonDBus::self(), &UpmCommonDBus::userActiveSignal,
            UpmControlDBus::self(), &UpmControlDBus::setUserActive);

    initAcpiSocket();

    registerExternalInterface();
}

void UpmDaemon::dealSystemConfigChanged(const QString userName, const QString key, const QString value)
{
    if (userName == UpmControlDBus::self()->getUserName()) {
        return ;
    }

    QVariant::Type type = UpmGsettings::self()->getValueType(key);
    switch (type) {
    case QVariant::Int:
        UpmGsettings::self()->setGsettingsConfig(key, value.toInt());
        break;
    case QVariant::Bool:
        if ("true" == value) {
            UpmGsettings::self()->setGsettingsConfig(key, true);
        } else {
            UpmGsettings::self()->setGsettingsConfig(key, false);
        }
        break;
    case QVariant::String:
        UpmGsettings::self()->setGsettingsConfig(key, value);
        break;
    default:
        qInfo() << "config type error";
        break;
    }
}

void UpmDaemon::initAcpiSocket()
{
    m_socket = new QLocalSocket(this);
    connect(m_socket, &QLocalSocket::connected, this, [=]() { qDebug() << "acpi socket connected success"; });
    connect(m_socket, &QLocalSocket::readyRead, this, [=]() {
        QByteArray data = m_socket->readAll();
        QString str = QString(data).simplified();
        if (-1 != str.indexOf("thermal_zone LNXTHERM:00 000000f1 00000001", 0, Qt::CaseInsensitive)) {
            UpmCommonDBus::self()->controlLogin1Manager(LOGIN1_DBUS_SET_HIBERNATE);
        }
    });

    m_socket->connectToServer("/var/run/acpid.socket");
    qDebug() << m_socket->state();
}

void UpmDaemon::registerExternalInterface()
{
    m_externalInterface = new UpmExternalInterface(this);
    QDBusConnection connection = QDBusConnection::sessionBus();
    if (!connection.registerService("org.ukui.upower")) {
        qWarning() << "QDbus register service failed reason:" << connection.lastError();
        return;
    }

    if (!connection.registerObject("/upower/PowerManager", m_externalInterface,
                                   QDBusConnection::ExportAllSlots |
                                   QDBusConnection::ExportAllSignals)) {
        qWarning() << "QDbus register object failed reason:" << connection.lastError();
    }
}

void UpmDaemon::dealPowerPolicyAcChanged(QVariant value)
{
    int policy = value.toInt();

    switch (policy) {
    case power_policy_performance:
    case power_policy_balance:
    case power_policy_powersave:
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_POWER_POLICY_AC,
                                                   QString::number(policy));
        if (true == UpmUpowerDBus::self()->getAcOnlineState()) {
            UpmControlDBus::self()->controlPowerManagement(UPM_DBUS_METHOD_SET_PC_POLICY, policy);
        }
        qDebug() << "power policy on ac:" << g_policyList[policy];
        break;
    default:
        qInfo() << "ac policy index error:" << policy;
        break;
    }
}

void UpmDaemon::dealPowerPolicyBatteryChanged(QVariant value)
{
    int policy = value.toInt();

    switch (policy) {
    case power_policy_performance:
    case power_policy_balance:
    case power_policy_powersave:
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY,
                                                   QString::number(policy));
        if (false == UpmUpowerDBus::self()->getAcOnlineState()) {
            UpmControlDBus::self()->controlPowerManagement(UPM_DBUS_METHOD_SET_PC_POLICY, policy);
        }
        qDebug() << "power policy on battery:" << g_policyList[policy];
        if (true == m_lowPower->getBatterySaveSwitch() && policy != power_policy_powersave) {
            UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_BATTERY_SAVE_SWITCH, false);
            if (true == m_lowPower->getBatteryLowState()) {
                UpmGsettings::self()->setGsettingsConfig(GSETTINGS_KEY_LOW_BATTERY_AUTO_SAVE, false);
            }
        }
        break;
    default:
        qInfo() << "battery policy index error:" << policy;
        break;
    }
}

void UpmDaemon::dealPowerPolicyBatteryBackupChanged(QVariant value)
{
    int policy = value.toInt();

    switch (policy) {
    case power_policy_performance:
    case power_policy_balance:
    case power_policy_powersave:
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_POWER_POLICY_BATTERY_BACKUP,
                                                   QString::number(policy));
        qDebug() << "backup power policy on battery:" << g_policyList[policy];
        break;
    default:
        qInfo() << "backup battery policy index error:" << policy;
        break;
    }
}
