/*
 * Copyright 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 <http://www.gnu.org/licenses/>.
 */

#include "powerwindow.h"
#include "xatom-helper.h"
#include "qdesktopwidget.h"

#include <QApplication>
#include <QTimer>
#include <KWindowEffects>
#include <ukuistylehelper/ukuistylehelper.h>
#include <windowmanager/windowmanager.h>

#define ORG_UKUI_STYLE "org.ukui.style"
#define POWER_MANAGER_SETTINGS "org.ukui.power-manager"
#define SYSTEM_FONT_SIZE "systemFontSize"
#define STYLE_NAME "styleName"

#define MARGIN 8

#define TRANSPARENCY_SETTINGS "org.ukui.control-center.personalise"
#define TRANSPARENCY_KEY "transparency"

#define POWER_POLICY_AC "powerPolicyAc"
#define POWER_POLICY_BATTERY "powerPolicyBattery"

powerwindow::powerwindow(QWidget *parent) : QWidget(parent)
{
    qDebug() << " power window init start";
    initPlatformType();
    setWindowProperty(); //设置窗口属性
    initgsetting();
    initUI();            //初始化UI
    setSliderValue();

    watchTranspartency();

    if (true == m_isWayland) {
        kdk::UkuiStyleHelper::self()->removeHeader(this);
        kdk::WindowManager::setSkipTaskBar(this->windowHandle(), true);
        kdk::WindowManager::setSkipSwitcher(this->windowHandle(), true);
        resetWindowPosition();
    }

    //监听屏幕改变的信号
    connect(QApplication::desktop(), &QDesktopWidget::resized, this, [=]() {
        QTimer::singleShot(1000, this, [=]() {
            resetWindowPosition();
        });
    });
    connect(QApplication::desktop(), &QDesktopWidget::screenCountChanged, this, [=]() {
        resetWindowPosition();
    });
    connect(QApplication::desktop(), &QDesktopWidget::primaryScreenChanged, this, [=]() {
        resetWindowPosition();
    });

    installEventFilter(this);
}

powerwindow::~powerwindow()
{
    if (nullptr != m_transparencyGsettings) {
        delete m_transparencyGsettings;
        m_transparencyGsettings = nullptr;
    }
}

void powerwindow::setWindowProperty()
{
    //设置任务栏无显示
    setWindowOpacity(1);
    setAttribute(Qt::WA_TranslucentBackground); //设置窗口背景透明
    setProperty("useSystemStyleBlur", true);    //设置毛玻璃效果
    setProperty("useStyleWindowManager", false);

    if (false == m_isWayland) {
        KWindowEffects::enableBlurBehind(this->winId(), true);
        // 添加窗管协议
        MotifWmHints hints;
        hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
        hints.functions = MWM_FUNC_ALL;
        hints.decorations = MWM_DECOR_BORDER;
        XAtomHelper::getInstance()->setWindowMotifHint(this->winId(), hints);
    }
}

void powerwindow::initUI()
{
    this->setFixedSize(420, 265 + m_deviceNum * 60);

    m_pmainlayout = new QVBoxLayout(this);
    m_firstlayout = new QHBoxLayout(this);
    m_toplayout = new QHBoxLayout(this);
    m_lastlayout = new QHBoxLayout(this);
    m_statelayout = new QHBoxLayout(this);

    m_firstwidget = new QWidget(this);
    m_topwidget = new QWidget(this);
    m_lastWidget = new QWidget(this);
    m_statewidget = new QWidget(this);

    m_iconButton = new QPushButton(this);
    m_iconButton->setFixedSize(QSize(48, 65));
    m_iconButton->setIconSize(QSize(30, 30));
    m_iconButton->setStyle(new CustomStyle);
    m_iconButton->setProperty("useIconHighlightEffect", 0x10);
    m_iconButton->setFlat(true);
    m_iconButton->setAttribute(Qt::WA_TransparentForMouseEvents);

    m_percentageLabel = new QLabel(this);
    setPercentageLabelFontsize();

    m_powerStateLabel = new QLabel(this);

    m_segmentationLine_1 = new Divider(this);
    m_segmentationLine_2 = new Divider(this);

    m_StateSlider = new KSlider(this);
    m_StateSlider->setOrientation(Qt::Orientation::Horizontal);
    m_StateSlider->setSliderType(KSliderType::SingleSelectSlider);
    m_StateSlider->setMaximum(2);
    m_StateSlider->setSingleStep(1);
    m_StateSlider->setPageStep(1);
    m_StateSlider->setFixedWidth(372);
    m_StateSlider->setProperty("needTranslucent", true);
    m_StateSlider->setTranslucent(true);
    connect(m_StateSlider, &KSlider::valueChanged, this, &powerwindow::sliderValueChanged);

    m_enduranceIconButtun = new QToolButton(this);
    m_enduranceIconButtun->setIconSize(QSize(16, 16));
    m_enduranceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_enduranceIconButtun->setProperty("useIconHighlightEffect", 0x2);
    m_enduranceIconButtun->setStyle(new CustomStyle);
    QIcon icon1 = QIcon::fromTheme("ukui-eco-symbolic");
    m_enduranceIconButtun->setIcon(icon1);

    m_enduranceIconButtun->setText(tr("Endurance"));

    m_performanceIconButtun = new QToolButton(this);
    m_performanceIconButtun->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    m_performanceIconButtun->setProperty("useIconHighlightEffect", 0x2);
    m_performanceIconButtun->setStyle(new CustomStyle);
    QIcon icon2 = QIcon::fromTheme("ukui-performance-symbolic");
    m_performanceIconButtun->setIcon(icon2);
    m_performanceIconButtun->setText(tr("Performance"));

    //电源设置按钮
    m_settingLabel = new KyLable(this);
    m_settingLabel->setText(tr("PowerSettings"));

    m_toplabel = new QLabel(this);
    m_toplabel->setText(tr("PowerMode"));
    m_toplayout->setContentsMargins(24, 0, 24, 0);
    m_toplayout->setSpacing(0);
    m_toplayout->addWidget(m_toplabel);
    m_toplayout->addItem(new QSpacerItem(10, 2));
    m_topwidget->setLayout(m_toplayout);

    //第一行布局
    m_firstlayout->setContentsMargins(18, 0, 24, 0);
    m_firstlayout->setSpacing(0);
    m_firstlayout->addWidget(m_iconButton, 0, Qt::AlignLeft | Qt::AlignVCenter);
    m_firstlayout->addWidget(m_percentageLabel, 0, Qt::AlignLeft | Qt::AlignVCenter);
    m_firstlayout->addStretch();
    m_firstlayout->addWidget(m_powerStateLabel, 0, Qt::AlignRight | Qt::AlignVCenter);

    m_firstwidget->setLayout(m_firstlayout);

    //滑动条下方标识布局
    m_statelayout->setContentsMargins(18, 0, 5, 0);
    m_statelayout->setSpacing(0);
    m_statelayout->addWidget(m_enduranceIconButtun, 0, Qt::AlignLeft | Qt::AlignCenter);
    m_statelayout->addStretch();
    m_statelayout->addWidget(m_performanceIconButtun, 0, Qt::AlignRight);
    m_statewidget->setLayout(m_statelayout);

    //电源设置按钮布局
    m_lastlayout->setContentsMargins(24, 0, 24, 0);
    m_lastlayout->setSpacing(0);
    m_lastlayout->addWidget(m_settingLabel);
    m_lastlayout->addStretch();
    m_lastWidget->setLayout(m_lastlayout);
    m_settingLabel->setCursor(Qt::PointingHandCursor);

    //总体布局
    m_pmainlayout->setContentsMargins(0, 0, 0, 0);
    m_pmainlayout->setSpacing(0);
    m_pmainlayout->addWidget(m_topwidget);
    m_pmainlayout->addWidget(m_segmentationLine_1);
    m_pmainlayout->addSpacing(12);
    m_pmainlayout->addWidget(m_firstwidget);
    m_pmainlayout->addSpacing(0);
    m_pmainlayout->addWidget(m_StateSlider, 0, Qt::AlignCenter);
    m_pmainlayout->addSpacing(0);
    m_pmainlayout->addWidget(m_statewidget);
    m_pmainlayout->addWidget(m_segmentationLine_2);
    m_pmainlayout->addWidget(m_lastWidget);
    this->setLayout(m_pmainlayout);
}

void powerwindow::initgsetting()
{
    const QByteArray styleId(ORG_UKUI_STYLE);
    if (QGSettings::isSchemaInstalled(styleId)) {
        m_styleSettings = new QGSettings(styleId);
        if (m_styleSettings->keys().contains(SYSTEM_FONT_SIZE)) {
            m_sysFontSize = m_styleSettings->get(SYSTEM_FONT_SIZE).toDouble();
        }
        connect(m_styleSettings, &QGSettings::changed, this, [=](const QString &key) {
            if (key == SYSTEM_FONT_SIZE) {
                m_sysFontSize = m_styleSettings->get(SYSTEM_FONT_SIZE).toDouble();
                setPercentageLabelFontsize();
                if (true == m_acOnlineChange) {
                    setPowerStateLabelForAcOnlineChanged();
                } else {
                    setPowerStateLabelForBatteryInfoChanged();
                }
            }
            if (key == STYLE_NAME) {
                m_iconButton->setIcon(QIcon::fromTheme(m_iconName));
            }
        });
    }

    const QByteArray powerId(POWER_MANAGER_SETTINGS);
    m_PowerManagerGsettings = new QGSettings(powerId);
    connect(m_PowerManagerGsettings, &QGSettings::changed, this, [=](const QString &key) {
        if (key == POWER_POLICY_AC || key == POWER_POLICY_BATTERY) {
            qDebug() << "m_PowerManagerGsettings changed !";
            setSliderValue();
        }
    });
}

void powerwindow::initPlatformType()
{
    if ("wayland" == qgetenv("XDG_SESSION_TYPE")) {
       m_isWayland = true;
    }
    qDebug() << "Platform is wayland:" << m_isWayland;
}

void powerwindow::setIconName(QString iconName)
{
    m_iconName = iconName;
    m_iconButton->setIcon(QIcon::fromTheme(m_iconName));
}

void powerwindow::setAcOnlineState(bool acOnlineState)
{
    if (m_acOnlineState == acOnlineState) {
        return;
    }
    m_acOnlineState = acOnlineState;
    if (true == m_acOnlineState) {
        m_toplabel->setText(tr("PowerMode"));
    } else {
        m_toplabel->setText(tr("BatteryMode"));
    }
    setSliderValue();
}

void powerwindow::setBatteryState(int iBatteryState)
{
    if (m_batteryState == iBatteryState) {
        m_batteryStateChanged = false;
    } else {
        m_batteryStateChanged = true;
        m_batteryState = iBatteryState;
        setSliderValue();
    }
}

void powerwindow::setBatteryPercentage(int iBatteryPercentage)
{
    m_batteryPercentage = iBatteryPercentage;
    m_percentageLabel->setText(QString("%1%").arg(m_batteryPercentage));
}

void powerwindow::setShowPowerLeftTime(int iShowPowerLeftTime)
{
    m_showBatteryLeftTime = iShowPowerLeftTime;
}

void powerwindow::setBatteryLeftTime(qlonglong timeToFull, qlonglong timeToEmpty)
{
    m_timeToFull = timeToFull;
    m_timeToEmpty = timeToEmpty;
}

void powerwindow::setPowerStateLabelForAcOnlineChanged()
{
    if (true == m_acOnlineState) {
        if (100 == m_batteryPercentage) {
            m_powerStateLabel->setText(tr("fully charged"));
        } else {
            m_powerStateLabel->setText(tr("Charging"));
        }
    } else {
        m_powerStateLabel->setText(tr("Discharging"));
    }
    m_acOnlineChange = true;
}

void powerwindow::setPowerStateLabelForBatteryInfoChanged()
{
    QString power_state_text("");
    int hour = 0;
    int minute = 0;

    switch (m_batteryState) {
        case battery_state_unknown:
        case battery_state_fully:
            if (100 == m_batteryPercentage) {
                power_state_text = QString(tr("fully charged"));
            }
            break;
        case battery_state_charging:
            if (false == m_showBatteryLeftTime || 0 == m_timeToFull
            || true == m_batteryStateChanged || m_batteryPercentage > 95) {
                if (100 == m_batteryPercentage) {
                    power_state_text = QString(tr("fully charged"));
                } else {
                    power_state_text = QString(tr("Charging"));
                }
            } else {
                hour = m_timeToFull / 3600;
                minute = ((m_timeToFull) % 3600) / 60;
                if (0 == hour) {
                    power_state_text = QString(tr("%1 minutes \nuntil fully charged")).arg(minute);
                } else if (hour > 10) {
                    power_state_text = QString(tr("Charging"));
                } else {
                    if (1 == hour) {
                        if (1 == minute) {
                            power_state_text = QString(tr("%1 hour %2 minute \nuntil fully charged"))
                                    .arg(hour).arg(minute);
                        } else if (0 == minute) {
                            power_state_text = QString(tr("%1 hour \nuntil fully charged")).arg(hour);
                        } else {
                            power_state_text = QString(tr("%1 hour %2 minutes \nuntil fully charged"))
                                    .arg(hour).arg(minute);
                        }
                    } else {
                        if (1 == minute) {
                            power_state_text = QString(tr("%1 hours %2 minute \nuntil fully charged"))
                                    .arg(hour).arg(minute);
                        } else if (0 == minute) {
                            power_state_text = QString(tr("%1 hours \nuntil fully charged")).arg(hour);
                        } else {
                            power_state_text = QString(tr("%1 hours %2 minutes \nuntil fully charged"))
                                    .arg(hour).arg(minute);
                        }
                    }
                }
            }
            break;
        case battery_state_discharging:
            if (false == m_showBatteryLeftTime || 0 == m_timeToEmpty
            || true == m_batteryStateChanged) {
                power_state_text = QString(tr("Discharging"));
            } else {
                hour = m_timeToEmpty / 3600;
                minute = ((m_timeToEmpty) % 3600) / 60;
                if (0 == hour) {
                    power_state_text = QString(tr("%1 minutes \nremaining")).arg(minute);
                } else if (hour > 20) {
                    power_state_text = QString(tr("Discharging"));
                } else {
                    if (1 == hour) {
                        if (1 == minute) {
                            power_state_text = QString(tr("%1 hour %2 minute \nremaining"))
                                    .arg(hour).arg(minute);
                        } else if (0 == minute) {
                            power_state_text = QString(tr("%1 hour \nremaining"))
                                    .arg(hour);
                        } else {
                            power_state_text = QString(tr("%1 hour %2 minutes \nremaining"))
                                    .arg(hour).arg(minute);
                        }
                    } else {
                        if (1 == minute) {
                            power_state_text = QString(tr("%1 hours %2 minute \nremaining"))
                                    .arg(hour).arg(minute);
                        } else if (0 == minute) {
                            power_state_text = QString(tr("%1 hours \nremaining"))
                                    .arg(hour);
                        } else {
                            power_state_text = QString(tr("%1 hours %2 minutes \nremaining"))
                                    .arg(hour).arg(minute);
                        }
                    }
                }
            }
        default:
            break;
    }
    m_powerStateLabel->setText(power_state_text);
    m_acOnlineChange = false;
}

void powerwindow::setPercentageLabelFontsize()
{
    QFont font;
    font.setPointSize((int)(m_sysFontSize * 1.5));
    m_percentageLabel->setFont(font);
}

void powerwindow::showPowerWindow()
{
    if (false == m_isWayland) {
        resetWindowPosition();
        KWindowSystem::setState(this->winId(), NET::SkipTaskbar | NET::SkipPager | NET::SkipSwitcher);
        this->show();
    } else {
        this->show();
        kdk::UkuiStyleHelper::self()->removeHeader(this);
        kdk::WindowManager::setSkipTaskBar(this->windowHandle(), true);
        kdk::WindowManager::setSkipSwitcher(this->windowHandle(), true);
        resetWindowPosition();
    }
}

void powerwindow::resetWindowPosition()
{
    QDBusInterface panelDBus("org.ukui.panel", "/panel/position", "org.ukui.panel", QDBusConnection::sessionBus());
    QDBusReply<QVariantList> reply = panelDBus.call("GetPrimaryScreenGeometry");
    switch (reply.value().at(4).toInt()) {
        case PanelUp:
            m_windowPositionRect = QRect(reply.value().at(0).toInt() + reply.value().at(2).toInt() - this->width() - MARGIN,
                         reply.value().at(1).toInt() + MARGIN,
                         this->width(), this->height());
            break;
        case PanelLeft:
            m_windowPositionRect = QRect(reply.value().at(0).toInt() + MARGIN,
                         reply.value().at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                         this->width(), this->height());
            break;
        case PanelRight:
            m_windowPositionRect = QRect(reply.value().at(0).toInt() + reply.value().at(2).toInt() - this->width() - MARGIN,
                         reply.value().at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                         this->width(), this->height());
            break;
        default:
            m_windowPositionRect = QRect(reply.value().at(0).toInt() + reply.value().at(2).toInt() - this->width() - MARGIN,
                         reply.value().at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
                         this->width(), this->height());
            break;
    }
    if (false == m_isWayland) {
        this->setGeometry(m_windowPositionRect);
    } else {
        kdk::WindowManager::setGeometry(this->windowHandle(), m_windowPositionRect);
    }
}

void powerwindow::watchTranspartency()
{
    const QByteArray transparency_id(TRANSPARENCY_SETTINGS);
    if (QGSettings::isSchemaInstalled(transparency_id)) {
        m_transparencyGsettings = new QGSettings(transparency_id);

        if (m_transparencyGsettings->keys().contains(TRANSPARENCY_KEY)) {
            m_transparency = m_transparencyGsettings->get(TRANSPARENCY_KEY).toDouble() * 255;
        }
        this->update();
        connect(m_transparencyGsettings, &QGSettings::changed, this, [=](const QString &key) {
            if (key == TRANSPARENCY_KEY) {
                m_transparency = m_transparencyGsettings->get(TRANSPARENCY_KEY).toDouble() * 255;
                this->update();
            }
        });
    } else {
        m_transparency = 0.75;
    }
}

void powerwindow::sliderValueChanged(int value)
{
    qDebug() << "ac online state:" << m_acOnlineState << "slider value:" << value;
    if (true == m_acOnlineState) {
        switch (value) {
            case 0:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, EnergySaving);
                m_StateSlider->setToolTip(tr("Better endurance"));
                break;
            case 1:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, Balance);
                m_StateSlider->setToolTip(tr("Better performance"));
                break;
            case 2:
                m_PowerManagerGsettings->set(POWER_POLICY_AC, Performance);
                m_StateSlider->setToolTip(tr("Best performance"));
                break;
            default:
                break;
        }
    } else {
        switch (value) {
            case 0:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, EnergySaving);
                m_StateSlider->setToolTip(tr("Better endurance"));
                break;
            case 1:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, Balance);
                m_StateSlider->setToolTip(tr("Better performance"));
                break;
            case 2:
                m_PowerManagerGsettings->set(POWER_POLICY_BATTERY, Performance);
                m_StateSlider->setToolTip(tr("Best performance"));
                break;
            default:
                break;
        }
    }
}

void powerwindow::setSliderValue()
{
    int policy = -1;
    if (true == m_acOnlineState) {
        policy = m_PowerManagerGsettings->get(POWER_POLICY_AC).toInt();
    } else {
        policy = m_PowerManagerGsettings->get(POWER_POLICY_BATTERY).toInt();
    }
    qDebug() << "ac online state:" << m_acOnlineState << "policy:" << policy;

    switch (policy) {
        case Performance:
            m_StateSlider->setValue(2);
            m_StateSlider->setToolTip(tr("Best performance"));
            break;
        case Balance:
            m_StateSlider->setValue(1);
            m_StateSlider->setToolTip(tr("Better performance"));
            break;
        case EnergySaving:
            m_StateSlider->setValue(0);
            m_StateSlider->setToolTip(tr("Better endurance"));
            break;
        default:
            break;
    }
}

void powerwindow::paintEvent(QPaintEvent *e)
{
    QStyleOption opt;
    opt.init(this);
    QPainter p(this);
    p.setPen(Qt::NoPen);
    QColor color = palette().color(QPalette::Base);
    color.setAlpha(m_transparency);
    QBrush brush = QBrush(color);
    p.setBrush(brush);

    p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    p.drawRect(opt.rect);
}

bool powerwindow::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == this) {
        if (event->type() == QEvent::WindowDeactivate) {
            hide();
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

void powerwindow::keyPressEvent(QKeyEvent *event)
{
    if (event->key() == Qt::Key_Escape) {
        hide();
    }
    QWidget::keyPressEvent(event);
}
