/*
 * 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, 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 "notice.h"
#include "appdetail.h"
#include "realizenotice.h"
#include "noticemenu.h"
#include "hoverwidget.h"
#include <QFileDialog>
#include <QTimer>
#include <QFileSystemWatcher>
#include <QSettings>
#include <QToolButton>
#include <QStandardPaths>
#include "interface/ukcccommon.h"
using namespace ukcc;

#define NOTICE_SCHEMA         "org.ukui.control-center.notice"
#define NEW_FEATURE_KEY       "show-new-feature"
#define ENABLE_NOTICE_KEY     "enable-notice"
#define SHOWON_LOCKSCREEN_KEY "show-on-lockscreen"

#define AUTOSTARTDIR      "/etc/xdg/autostart/"

Notice::Notice() : mFirstLoad(true)
{
    pluginName = tr("Notice");
    pluginType = SYSTEM;
}

Notice::~Notice()
{
    if (!mFirstLoad) {

    }
}

QString Notice::plugini18nName()
{
    return pluginName;
}

int Notice::pluginTypes()
{
    return pluginType;
}

QWidget *Notice::pluginUi()
{
    if (mFirstLoad) {
        mFirstLoad = false;
        mNoticeWidget = new NoticeUi;
        mNoticeDBus = new QDBusInterface("org.ukui.ukcc.session",
                                         "/Notice",
                                         "org.ukui.ukcc.session.Notice",
                                         QDBusConnection::sessionBus(), this);
        if (!mNoticeDBus->isValid()) {
            qCritical() << "org.ukui.ukcc.session.Notice DBus error:" << mNoticeDBus->lastError();
        } else {
            QDBusConnection::sessionBus().connect("org.ukui.ukcc.session",
                                                  "/Notice",
                                                  "org.ukui.ukcc.session.Notice",
                                                  "changed",
                                                  this,
                                                  SLOT(keyChangedSlot(QString)));
            setupComponent();
            setupGSettings();
            initOriNoticeStatus();
        }
    }
    return mNoticeWidget;
}

const QString Notice::name() const
{
    return QStringLiteral("Notice");
}

bool Notice::isShowOnHomePage() const
{
    return false;
}

QIcon Notice::icon() const
{
    return QIcon::fromTheme("ukui-tool-symbolic");
}

bool Notice::isEnable() const
{
    return true;
}

void Notice::setupComponent()
{
    bool ischecked = mNoticeDBus->property("isAutostartDisturb").toBool();
    mNoticeWidget->getAutoOpenSwitchBtn()->setChecked(ischecked);
    QString starttime = mNoticeDBus->property("timeStart").toString();
    QString endtime = mNoticeDBus->property("timeEnd").toString();
    QStringList startlist = starttime.split(":");
    QStringList endlist = endtime.split(":");
    if (startlist.length() >= 2 && endlist.length() >= 2) {
        mNoticeWidget->getOpenTimeHCombox()->setCurrentText(startlist.at(0));
        mNoticeWidget->getOpenTimeMCombox()->setCurrentText(startlist.at(1));
        mNoticeWidget->getCloseTimeHCombox()->setCurrentText(endlist.at(0));
        mNoticeWidget->getCloseTimeMCombox()->setCurrentText(endlist.at(1));
    }
    setComBoxStatus(ischecked);

    mNoticeWidget->getAllowAlarmrWidget()->setChecked(mNoticeDBus->property("isAlarmClockDisturb").toBool());
    mNoticeWidget->getMultiScreenWidget()->setChecked(mNoticeDBus->property("isProjectionScreenDisturb").toBool());
    mNoticeWidget->getFullScreenWidget()->setChecked(mNoticeDBus->property("isFullScreenDisturb").toBool());

    ischecked = mNoticeDBus->property("isEnable").toBool();
    mNoticeWidget->getNoticeWidget()->setChecked(ischecked);
    setHiddenNoticeApp(ischecked);
}

void Notice::setupGSettings()
{

    connect(mNoticeWidget->getAutoOpenSwitchBtn(), &KSwitchButton::stateChanged, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether auto turn on do not disturb mode", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setNoticeDisturb", AUTOSTART_KEY, checked);
        setComBoxStatus(checked);
    });
    connect(mNoticeWidget->getMultiScreenWidget(), &SwitchWidget::stateChanged, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether auto turn on do not disturb mode when multi screen connection", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setNoticeDisturb", PROJECTIONSCREEN_KEY, checked);
    });
    connect(mNoticeWidget->getFullScreenWidget(), &SwitchWidget::stateChanged, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether auto turn on do not disturb mode when full screen mode", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setNoticeDisturb", FULLSCREEN_KEY, checked);
    });
    connect(mNoticeWidget->getAllowAlarmrWidget(), &SwitchWidget::stateChanged, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether allow alarm prompt at not disturb mode", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setNoticeDisturb", ALARMCLOCK_KEY, checked);
    });
    connect(mNoticeWidget->getOpenTimeHCombox(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index){
        Q_UNUSED(index);
        UkccCommon::buriedSettings(name(), "open time(hour) when auto turn on do not disturb mode", QString("settings"), mNoticeWidget->getOpenTimeHCombox()->currentText());
        mNoticeDBus->call("setNoticeDisturb", TIMESTART_KEY, QString("%1%2%3").arg(mNoticeWidget->getOpenTimeHCombox()->currentText()).arg(":").arg(mNoticeWidget->getOpenTimeMCombox()->currentText()));
    });

    connect(mNoticeWidget->getOpenTimeMCombox(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index){
        Q_UNUSED(index);
        UkccCommon::buriedSettings(name(), "open time(minute) when auto turn on do not disturb mode", QString("settings"), mNoticeWidget->getOpenTimeMCombox()->currentText());
        mNoticeDBus->call("setNoticeDisturb", TIMESTART_KEY, QString("%1%2%3").arg(mNoticeWidget->getOpenTimeHCombox()->currentText()).arg(":").arg(mNoticeWidget->getOpenTimeMCombox()->currentText()));
    });

    connect(mNoticeWidget->getCloseTimeHCombox(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index){
        Q_UNUSED(index);
        UkccCommon::buriedSettings(name(), "close time(hour) when auto turn on do not disturb mode", QString("settings"), mNoticeWidget->getCloseTimeHCombox()->currentText());
        mNoticeDBus->call("setNoticeDisturb", TIMEEND_KEY, QString("%1%2%3").arg(mNoticeWidget->getCloseTimeHCombox()->currentText()).arg(":").arg(mNoticeWidget->getCloseTimeMCombox()->currentText()));
    });

    connect(mNoticeWidget->getCloseTimeMCombox(), QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index){
        Q_UNUSED(index);
        UkccCommon::buriedSettings(name(), "close time(minute) when auto turn on do not disturb mode", QString("settings"), mNoticeWidget->getCloseTimeMCombox()->currentText());
        mNoticeDBus->call("setNoticeDisturb", TIMEEND_KEY, QString("%1%2%3").arg(mNoticeWidget->getCloseTimeHCombox()->currentText()).arg(":").arg(mNoticeWidget->getCloseTimeMCombox()->currentText()));
    });


    connect(mNoticeWidget->getNoticeWidget(), &SwitchWidget::stateChanged, [=](bool checked){
        UkccCommon::buriedSettings(name(), "whether to get the notification from the app", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setUkccNotice", ENABLE_NOTICE_KEY, checked);
        setHiddenNoticeApp(checked);
    });
}

void Notice::initItemUi(NoticeApp &app)
{
    SwitchWidget *baseWidget = new SwitchWidget(app.name);

    QLabel *iconLabel = new QLabel(baseWidget);
    iconLabel->setFixedSize(32, 32);
    setAppIcon(iconLabel, app.icon);
    mIconLabelMap[iconLabel] = app.icon;

    QToolButton *setBtn = new QToolButton(baseWidget);
    setBtn->setProperty("useButtonPalette", true);
    setBtn->setAutoRaise(true);
    setBtn->setPopupMode(QToolButton::InstantPopup);
    setBtn->setIcon(QIcon::fromTheme("view-more-horizontal-symbolic"));
    NoticeMenu *menu = new NoticeMenu(setBtn);
    menu->initStaus(app.voice, app.detail, app.show, app.mode);
    setBtn->setMenu(menu);

    baseWidget->insertWidget(0, iconLabel);
    baseWidget->insertWidget(2, setBtn, 1, Qt::AlignRight);
    baseWidget->setChecked(app.status);

    mNoticeWidget->getAppListWidget()->addWidget(baseWidget);

    connect(menu, &NoticeMenu::voiceSignals, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether prompt sound during notification", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setAppInfo", app.desktop, VOICE_KEY, checked);
    });

    connect(menu, &NoticeMenu::detailSignals, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether to show the message content in the lock screen interface", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setAppInfo", app.desktop, SHOW_DETAIL_KEY, checked);
    });

    connect(menu, &NoticeMenu::showSignals, [=](bool checked) {
        UkccCommon::buriedSettings(name(), "whether to show the notice in the lock screen interface", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setAppInfo", app.desktop, SHOW_SCREENLOCK_KEY, checked);
    });

    connect(menu, &NoticeMenu::styleBtnSignals, [=](int id) {
        QString str("mutative");
        if (id == 0)
            str = "mutative";
        else if (id == 1)
            str = "always";
        else if (id == 2)
            str = "none";
        UkccCommon::buriedSettings(name(), "set notice style", QString("settings"), str);
        mNoticeDBus->call("setAppInfo", app.desktop, STYLE_KEY, str);
    });

    connect(baseWidget, &SwitchWidget::stateChanged, [=](bool checked) {
        UkccCommon::buriedSettings(name(), app.desktop + " whether to start notification", QString("settings"), checked ? "true" : "false");
        mNoticeDBus->call("setAppInfo", app.desktop, MESSAGES_KEY, checked);
    });

}

void Notice::initOriNoticeStatus()
{
    QList <QVariant> list = mNoticeDBus->property("noticeAppList").toList();
    for (QVariant app : list) {
        NoticeApp info;
        const QDBusArgument &dbusArgs = app.value<QDBusArgument>();
        dbusArgs >> info;
        initItemUi(info);
    }
}

void Notice::setAppIcon(QLabel *label, const QString &icon)
{
    QFileInfo iconfile(icon);
    QPixmap pixmap;
    if (!QString(icon).isEmpty()) {
        QIcon currenticon
            = QIcon::fromTheme(icon,
                               QIcon(QString("/usr/share/pixmaps/"+icon
                                             +".png")));
        pixmap = currenticon.pixmap(QSize(32, 32));
    } else if (iconfile.exists()) {
        pixmap = QPixmap(iconfile.filePath()).scaled(32, 32);
    } else {
        pixmap = QPixmap(QString(":/img/plugins/autoboot/desktop.png"));
    }
    label->setPixmap(pixmap);
}

void Notice::setHiddenNoticeApp(bool status)
{
    mNoticeWidget->getAppListWidget()->setVisible(status);
}

void Notice::setComBoxStatus(bool status)
{
    mNoticeWidget->getOpenTimeHCombox()->setEnabled(status);;
    mNoticeWidget->getOpenTimeMCombox()->setEnabled(status);;
    mNoticeWidget->getCloseTimeHCombox()->setEnabled(status);;
    mNoticeWidget->getCloseTimeMCombox()->setEnabled(status);;
}

void Notice::keyChangedSlot(const QString &key)
{
    if (key == "iconThemeName") {
        for (auto it = mIconLabelMap.begin(); it != mIconLabelMap.end(); it++)
            setAppIcon(it.key(), it.value());
    }
}

const QDBusArgument &operator<<(QDBusArgument &argument, const NoticeApp &app) {
    argument.beginStructure();
    argument << app.desktop;
    argument << app.icon;
    argument << app.name;
    argument << app.status;
    argument << app.voice;
    argument << app.detail;
    argument << app.show;
    argument << app.mode;
    argument.endStructure();
    return argument;
}

const QDBusArgument &operator>>(const QDBusArgument &argument, NoticeApp &app)
{
    argument.beginStructure();
    argument >> app.desktop;
    argument >> app.icon;
    argument >> app.name;
    argument >> app.status;
    argument >> app.voice;
    argument >> app.detail;
    argument >> app.show;
    argument >> app.mode;
    argument.endStructure();
    return argument;
}
