/*
 * 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_systemidle.h"

UpmSystemIdle::UpmSystemIdle(QObject *parent) : QObject(parent)
{
    QStringList valueRange = {QString::number(300), QString::number(600),
                              QString::number(900), QString::number(1800),
                              QString::number(3600), QString::number(7200),
                              QString::number(10800), QString::number(-1)};
    m_turnoffDisplayAc = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_SLEEP_DISPLAY_AC,
                DEFAULE_SLEEP_DISPLAY_TIME, QVariant::Int,
                valueRange, false).toInt();
    m_turnoffDisplayBattery = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY,
                DEFAULE_SLEEP_DISPLAY_TIME, QVariant::Int,
                valueRange, false).toInt();
    m_systemSuspendAc = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_SLEEP_COMPUTER_AC,
                DEFAULE_SLEEP_COMPUTER_TIME, QVariant::Int,
                valueRange, false).toInt();
    m_systemSuspendBattery = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY,
                DEFAULE_SLEEP_COMPUTER_TIME, QVariant::Int,
                valueRange, false).toInt();

    valueRange.clear();
    valueRange << QString::number(50) << QString::number(100);
    m_idleBrightnessPercentage = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_IDLE_BRIGHTNESS,
                DEFAULE_IDLE_BRIGHTNESS, QVariant::Int,
                valueRange, true).toInt();
    if (m_idleBrightnessPercentage >= 50 && m_idleBrightnessPercentage < 100) {
        m_idleReduceBrightness = true;
    }

    valueRange.clear();
    valueRange << "true" << "false";
    m_idlePowerPolicyAuto = UpmCheckConfig::checkConfig(
                GSETTINGS_KEY_IDLE_POWER_POLICY_AUTO,
                false, QVariant::Bool,
                valueRange, false).toBool();

    connect(UpmGsettings::self(), &UpmGsettings::sleepDisplayAcChanged,
            this, [=](QVariant value) {
        m_turnoffDisplayAc = value.toInt();
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_SLEEP_DISPLAY_AC,
                                                   QString::number(m_turnoffDisplayAc));
    });
    connect(UpmGsettings::self(), &UpmGsettings::sleepDisplayBatteryChanged,
            this, [=](QVariant value) {
        m_turnoffDisplayBattery = value.toInt();
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_SLEEP_DISPLAY_BATTERY,
                                                   QString::number(m_turnoffDisplayBattery));
    });
    connect(UpmGsettings::self(), &UpmGsettings::sleepComputerAcChanged,
            this, [=](QVariant value) {
        m_systemSuspendAc = value.toInt();
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_SLEEP_COMPUTER_AC,
                                                   QString::number(m_systemSuspendAc));
    });
    connect(UpmGsettings::self(), &UpmGsettings::sleepComputerBatteryChanged,
            this, [=](QVariant value) {
        m_systemSuspendBattery = value.toInt();
        UpmControlDBus::self()->setUpmSystemConfig(GSETTINGS_KEY_SLEEP_COMPUTER_BATTERY,
                                                   QString::number(m_systemSuspendBattery));
    });

    connect(UpmCommonDBus::self(), &UpmCommonDBus::systemSleepStatus,
            this, &UpmSystemIdle::stopTimer);

    connect(UpmCommonDBus::self(), &UpmCommonDBus::systemIdleStatus,
            this, &UpmSystemIdle::dealSystemIdleStatus);

    m_turnOffDisplayTimer = new QTimer(this);
    connect(m_turnOffDisplayTimer, &QTimer::timeout,
            this, &UpmSystemIdle::dealTurnOffDisplay);
    m_systemSuspendTimer = new QTimer(this);
    connect(m_systemSuspendTimer, &QTimer::timeout,
            this, &UpmSystemIdle::dealSystemSuspend);
    m_reduceBrightnessTimer = new QTimer(this);
    connect(m_reduceBrightnessTimer, &QTimer::timeout,
            this, &UpmSystemIdle::dealReduceBrightness);
}

void UpmSystemIdle::dealSystemIdleStatus(bool systemIdle)
{
    qDebug() << "system enter idle:" << systemIdle;
    if (true == systemIdle) {
        startTimer();

        idleReduceBrightness();

        idleSwitchPowerPolicy();
    } else {
        stopTimer();

        recoveryBrightness();

        recoveryPowerPolicy();
    }
}

int UpmSystemIdle::getTurnOffDisplayTime()
{
    int turnOffDisplayTime = 0;

    if (true == UpmUpowerDBus::self()->getAcOnlineState()) {
        turnOffDisplayTime = m_turnoffDisplayAc - m_enterIdleTime;
    } else {
        turnOffDisplayTime = m_turnoffDisplayBattery - m_enterIdleTime;
    }
    return turnOffDisplayTime;
}

int UpmSystemIdle::getSystemSuspendTime()
{
    int systemSuspendTime = 0;

    if (true == UpmUpowerDBus::self()->getAcOnlineState()) {
        systemSuspendTime = m_systemSuspendAc - m_enterIdleTime;
    } else {
        systemSuspendTime = m_systemSuspendBattery - m_enterIdleTime;
    }
    return systemSuspendTime;
}

void UpmSystemIdle::idleReduceBrightness()
{
    if (false == m_idleReduceBrightness) {
        return ;
    }

    QVariant value;
    if (true == UpmGsettings::self()->getGsettingsConfig(GSETTINGS_KEY_BRIGHTNESS_AC, value)) {
        m_brightnessPercentage = value.toInt();
    }
    if (false == UpmUpowerDBus::self()->getAcOnlineState()) {
        m_actualPercentage = m_brightnessPercentage * m_idleBrightnessPercentage / 100;
        UpmControlDBus::self()->controlPowerManagement(UPM_DBUS_METHOD_SET_BRIGHTNESS_PERCENT,
                                                       m_actualPercentage);
    } else {
        m_actualPercentage = m_brightnessPercentage;
    }
}

void UpmSystemIdle::dealReduceBrightness()
{
    if (false == m_idleReduceBrightness) {
        QVariant value;
        if (true == UpmGsettings::self()->getGsettingsConfig(
                    GSETTINGS_KEY_BRIGHTNESS_AC, value)) {
            m_brightnessPercentage = value.toInt();
        }
        m_actualPercentage = m_brightnessPercentage * 0.7;
    } else {
        m_actualPercentage = m_actualPercentage * 0.7;
    }
    UpmControlDBus::self()->controlPowerManagement(UPM_DBUS_METHOD_SET_BRIGHTNESS_PERCENT,
                                                   m_actualPercentage);
    m_reduceBrightnessTimer->stop();
}

void UpmSystemIdle::recoveryBrightness()
{
    if (m_actualPercentage != m_brightnessPercentage) {
        UpmControlDBus::self()->controlPowerManagement(UPM_DBUS_METHOD_SET_BRIGHTNESS_PERCENT,
                                                       m_brightnessPercentage);
    }
}

void UpmSystemIdle::idleSwitchPowerPolicy()
{
    int powerPolicy = getPowerPolicy();

    qDebug() << "idleSwitchPowerPolicy:" << powerPolicy;
    if (power_policy_powersave != powerPolicy) {
        if (true == m_idlePowerPolicyAuto) {
            UpmControlDBus::self()->controlPowerManagement(
                        UPM_DBUS_METHOD_SET_PC_POLICY, power_policy_powersave);
        } else {
            UpmControlDBus::self()->controlPowerManagement(
                        UPM_DBUS_METHOD_SET_GPU_POLICY, power_policy_powersave);
        }
    }
}

void UpmSystemIdle::recoveryPowerPolicy()
{
    int powerPolicy = getPowerPolicy();

    if (power_policy_powersave != powerPolicy) {
        if (true == m_idlePowerPolicyAuto) {
            UpmControlDBus::self()->controlPowerManagement(
                        UPM_DBUS_METHOD_SET_PC_POLICY, powerPolicy);
        } else {
            UpmControlDBus::self()->controlPowerManagement(
                        UPM_DBUS_METHOD_SET_GPU_POLICY, powerPolicy);
        }
    }
}

int UpmSystemIdle::getPowerPolicy()
{
    QVariant value;

    if (true == UpmUpowerDBus::self()->getAcOnlineState()) {
        if (true == UpmGsettings::self()->getGsettingsConfig(
                    GSETTINGS_KEY_POWER_POLICY_AC, value)) {
            return value.toInt();
        }
    } else {
        if (true == UpmGsettings::self()->getGsettingsConfig(
                    GSETTINGS_KEY_POWER_POLICY_BATTERY, value)) {
            return value.toInt();
        }
    }

    return power_policy_unknown;
}

void UpmSystemIdle::dealTurnOffDisplay()
{
    UpmControlDBus::self()->delayLockScreen("idle");
    UpmControlDBus::self()->controlDisplay("off");
    UpmControlDBus::self()->turnOffDisplaySignal();
    m_turnOffDisplayTimer->stop();
}

void UpmSystemIdle::dealSystemSuspend()
{
    UpmCommonDBus::self()->controlLogin1Manager(LOGIN1_DBUS_SET_SUSPEND);
    m_systemSuspendTimer->stop();
}

void UpmSystemIdle::startTimer()
{
    int turnOffDisplayTime = getTurnOffDisplayTime();
    int systemSuspendTime = getSystemSuspendTime();
    int reduceBrightness = -1;

    if (turnOffDisplayTime > 0) {
        m_turnOffDisplayTimer->start(turnOffDisplayTime * 1000);
    } else {
        qDebug() << "turn off display timer not started!";
    }
    if (systemSuspendTime > 0) {
        m_systemSuspendTimer->start(systemSuspendTime * 1000);
    } else {
        qDebug() << "system suspend timer not started!";
    }

    if (turnOffDisplayTime > 0) {
        reduceBrightness = turnOffDisplayTime - 10;
        m_reduceBrightnessTimer->start(reduceBrightness * 1000);
        qDebug() << "reduce brightness time:" << reduceBrightness;
    }
}

void UpmSystemIdle::stopTimer()
{
    qDebug() << "stop timer";
    if (m_turnOffDisplayTimer->isActive()) {
        m_turnOffDisplayTimer->stop();
    }
    if (m_systemSuspendTimer->isActive()) {
        m_systemSuspendTimer->stop();
    }
    if (m_reduceBrightnessTimer->isActive()) {
        m_reduceBrightnessTimer->stop();
    }
}
