/*
 * 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 "vino.h"
#include "ukcccommon.h"
using namespace ukcc;

#include <QGSettings>

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

Vino::~Vino()
{
}

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

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

QWidget *Vino::pluginUi()
{
    if (mFirstLoad) {
        mFirstLoad = false;
        mVinoWidget = new VinoUi;
        mServiceDbus = new QDBusInterface("com.control.center.qt.systemdbus",
                                         "/",
                                         "com.control.center.interface",
                                         QDBusConnection::systemBus(), this);
        mVinoDBus = new QDBusInterface("org.ukui.ukcc.session",
                                        "/Vino",
                                        "org.ukui.ukcc.session.Vino",
                                        QDBusConnection::sessionBus(), this);
        if (!mVinoDBus->isValid()) {
            qCritical() << "org.ukui.ukcc.session.Vino DBus error:" << mVinoDBus->lastError();
        } else {
            initStatus();
            initServiceStatus();
            initConnection();
        }
    }

    return mVinoWidget;
}

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

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

QIcon Vino::icon() const
{
    return QIcon::fromTheme("folder-remote-symbolic");
}

bool Vino::isEnable() const
{
    return !UkccCommon::isCommunity() && !UkccCommon::isWayland() && isExistVino();
}

bool Vino::isExistVino() const
{
    return QGSettings::isSchemaInstalled(QByteArray("org.gnome.Vino"));
}

void Vino::setVinoService(bool status)
{
    QDBusInterface vinoIfc("org.ukui.SettingsDaemon",
                           "/org/ukui/SettingsDaemon/Sharing",
                           "org.ukui.SettingsDaemon.Sharing",
                           QDBusConnection::sessionBus());
    if (vinoIfc.isValid()) {
        if (status) {
            vinoIfc.call("EnableService", "vino-server");
        } else {
            vinoIfc.call("DisableService", "vino-server");
        }
    }
}

void Vino::enabledSlot(bool status)
{
    if (status) {
        mVinoDBus->call("setVinoKey", kEnableKey, true);
        initServiceStatus();
        if (isExsitXrdp) {
            if (mServiceDbus->isValid()) {
                mVinoWidget->getXrdpEnableWidget()->setChecked(status);
                setXrdpService(status);
            }
            mVinoWidget->getXrdpEnableWidget()->setVisible(true);
        }
        mVinoWidget->getVinoEnableWidget()->setChecked(status);
        vinoEnableSlot(status);
        mVinoWidget->getVinoFrame()->setVisible(true);
    } else {
        mVinoDBus->call("setVinoKey", kEnableKey, false);
        if (isExsitXrdp) {
            mVinoDBus->call("setVinoKey", kXrdpEnableKey, status);
            mVinoWidget->getXrdpEnableWidget()->hide();
            if (mServiceDbus->isValid()) {
                setXrdpService(false);
            }
            mVinoWidget->getXrdpEnableWidget()->blockSignals(true);
            mVinoWidget->getXrdpEnableWidget()->setChecked(false);
            mVinoWidget->getXrdpEnableWidget()->blockSignals(false);
        }
        mVinoDBus->call("setVinoKey", kVinoEnableKey, status);
        vinoEnableSlot(false);
        mVinoWidget->getVinoFrame()->setVisible(false);
    }
}

void Vino::xrdpEnabledSlot(bool status)
{
    mVinoDBus->call("setVinoKey", kXrdpEnableKey, status);
    if (isExsitXrdp) {
        if (mServiceDbus->isValid()) {
            setXrdpService(status);
        }
    } else {
        mVinoWidget->getXrdpEnableWidget()->setVisible(false);
    }

}
void Vino::vinoEnableSlot(bool status)
{
    mVinoWidget->setFrameVisible(status);
    setVinoService(status);
}

void Vino::viewBoxSlot(bool status)
{
    mVinoDBus->call("setVinoKey", kVinoViewOnlyKey, !status);
}

void Vino::accessSlot(bool status)
{
    mVinoDBus->call("setVinoKey", kVinoPromptKey, status);
}

void Vino::pwdEnableSlot(bool status)
{
    if (status) {
        mVinoWidget->getPwdLabel()->setVisible(secpwd == "keyring" ? false:true);
        if (mVinoWidget->getPwdLabel()->isVisible()) {
            mVinoWidget->getPwdLabel()->setText(QByteArray::fromBase64(mVinoDBus->property("password").toString().toLatin1()));
            mVinoDBus->call("setVinoKey", kAuthenticationKey, "vnc");
        } else {
            pwdEditSlot();
            if (mVinoDBus->property("method").toString() == "none") {
                mVinoWidget->getSecurityPwdWidget()->setChecked(false);
            }
        }

        mVinoWidget->getPwdLabel()->setVisible(mVinoWidget->getSecurityPwdWidget()->isChecked());
        mVinoWidget->getPwdEditBtn()->setVisible(secpwd == "keyring" ? false:true);

    } else {
        mVinoWidget->getPwdLabel()->setVisible(false);
        mVinoWidget->getPwdEditBtn()->setVisible(false);
        mVinoDBus->call("setVinoKey", kAuthenticationKey, "none");
    }
}

void Vino::pwdEditSlot()
{
    InputPwdDialog *dialog = new InputPwdDialog(mVinoWidget);
    dialog->exec();
    mVinoWidget->getPwdLabel()->setText(QByteArray::fromBase64(mVinoDBus->property("password").toString().toLatin1()));
}

void Vino::initConnection()
{
    connect(mVinoWidget->getEnableWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), mVinoWidget->getEnableWidget()->objectName(), QString("settings"), status ? "true" : "false");
        enabledSlot(status);
    });

    connect(mVinoWidget->getXrdpEnableWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), mVinoWidget->getXrdpEnableWidget()->objectName(), QString("settings"), status ? "true" : "false");
        xrdpEnabledSlot(status);
    });

    connect(mVinoWidget->getVinoEnableWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), mVinoWidget->getVinoEnableWidget()->objectName(), QString("settings"), status ? "true" : "false");
        vinoEnableSlot(status);
    });
    connect(mVinoWidget->getViewWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), "Allow connection to control screen", QString("settings"), status ? "true" : "false");
        viewBoxSlot(status);
    });
    connect(mVinoWidget->getSecurityWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), "You must confirm every visit for this machine", QString("settings"), status ? "true" : "false");
        accessSlot(status);
    });
    connect(mVinoWidget->getSecurityPwdWidget(), &SwitchWidget::stateChanged, this, [=](bool status) {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), "Require user to enter this password: ", QString("settings"), status ? "true" : "false");
        pwdEnableSlot(status);
    });
    connect(mVinoWidget->getPwdEditBtn(), &QPushButton::clicked, this, [=]() {
        UkccCommon::buriedSettings(QStringLiteral("Vino"), "set password", QString("clicked"));
        pwdEditSlot();
    });
}

void Vino::initStatus()
{
    bool isShared = mVinoDBus->property("isViewOnly").toBool();
    bool isPrompt = mVinoDBus->property("isPrompt").toBool();

    QString pwd = mVinoDBus->property("method").toString();
    secpwd = mVinoDBus->property("password").toString();
    mVinoWidget->getPwdEditBtn()->setVisible(secpwd == "keyring" ? false:true);

    mVinoWidget->getSecurityWidget()->setChecked(isPrompt);
    mVinoWidget->getViewWidget()->setChecked(!isShared);
    if (pwd == "vnc") {
        if (secpwd == "keyring") {
            mVinoWidget->getSecurityPwdWidget()->setChecked(false);
            mVinoWidget->getPwdLabel()->hide();
            mVinoWidget->getPwdEditBtn()->hide();
            mVinoDBus->call("setVinoKey", kAuthenticationKey, "none");
        } else {
            mVinoWidget->getSecurityPwdWidget()->setChecked(true);
            mVinoWidget->getPwdLabel()->setText(QByteArray::fromBase64(secpwd.toLatin1()));
        }
    } else {
        mVinoWidget->getSecurityPwdWidget()->setChecked(false);
        mVinoWidget->getPwdLabel()->setVisible(false);
        mVinoWidget->getPwdEditBtn()->setVisible(false);
    }

    mVinoWidget->setFrameVisible(mVinoDBus->property("isActive").toBool());
}

void Vino::initServiceStatus()
{
    bool isEnabled = mVinoDBus->property("isEnable").toBool();
    if (isEnabled) {
        mVinoWidget->getEnableWidget()->setChecked(true);
        XrdpServiceStatus xrdpstatus = getXrdpServiceStatus();
        switch (xrdpstatus) {
        case NONE:
            mVinoWidget->getXrdpEnableWidget()->hide();
            isExsitXrdp = false;
            break;
        case RUNNING:
            mVinoWidget->getXrdpEnableWidget()->setChecked(true);
            break;
        case INACTIVE:
            mVinoWidget->getXrdpEnableWidget()->setChecked(false);
            break;
        }
    } else {
        mVinoWidget->getEnableWidget()->setChecked(false);
        mVinoWidget->getXrdpEnableWidget()->hide();
        mVinoWidget->getVinoFrame()->hide();
    }
}

XrdpServiceStatus Vino::getXrdpServiceStatus()
{
    QProcess process;
    QString cmd = "systemctl status xrdp.service | grep Active:";
    process.start("bash", QStringList() <<"-c" << cmd);
    process.waitForFinished();
    QString strResult = process.readAllStandardOutput()+process.readAllStandardError();
    if (strResult.replace("\n", "") == "Unit xrdp.service could not be found.") {
        return NONE;
    }
    cmd = "systemctl is-failed xrdp.service";
    process.start("bash", QStringList() <<"-c" << cmd);
    process.waitForFinished();
    strResult = process.readAllStandardOutput()+process.readAllStandardError();
    if ((strResult.replace("\n", "") == "active"))
        return RUNNING;
    else
        return INACTIVE;

}

void Vino::setXrdpService(bool status)
{
    QTimer::singleShot(1, this, [=]() {
        QtConcurrent::run([=]() {
            mServiceDbus->call("setXrdpService", status);
        });

    });
}
