/*
 * 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 "screenlockui.h"
#include <QImageReader>

ScreenlockUi::ScreenlockUi()
{
    setAttribute(Qt::WA_DeleteOnClose);
    uiLayout         = new QVBoxLayout(this);
    screenlockLayout = new QVBoxLayout(this);
    relateLayout     = new QVBoxLayout(this);
    uiLayout->addLayout(screenlockLayout);
    uiLayout->addLayout(relateLayout);
    uiLayout->addStretch();
    uiLayout->setSpacing(40);
    uiLayout->setMargin(0);
    initUi();
}

ScreenlockUi::~ScreenlockUi()
{

}

void ScreenlockUi::initUi()
{
    initScreenLock();
    initRelateSet();
#ifdef Nile
    initLeavLockStatus();
#endif
    initSignals();
}

void ScreenlockUi::initScreenLock()
{
    wallpaperTitleLabel = new TitleLabel(this);
    previewFrame        = new UkccFrame(this);
    previewLayout       = new QHBoxLayout(previewFrame);
    previewLabel        = new QLabel(this);
    centerGroup         = new SettingGroup(this);
    //~ contents_path /Screenlock/Show picture of screenlock on screenlogin
    showPicWidget       = new SwitchWidget(tr("Show picture of screenlock on screenlogin"), centerGroup);
#ifdef Nile
    btLeaveLockWidget   = new SwitchWidget(tr("Leave lock (System will be locked when the paired phone gone)"), centerGroup);
    bluetoothWidget     = new ComboxWidget(tr("Specified device"), centerGroup);
    setBtWidget         = new PushButtonWidget(tr("No paired phone. Please turn to 'Bluetooth' to pair."), centerGroup);
    noBtWidget          = new UkccFrame(centerGroup,UkccFrame::None,true);
#endif
    picBtnFrame         = new UkccFrame(centerGroup);
    picBtnLayout        = new QVBoxLayout(picBtnFrame);
    pictureFrame        = new UkccFrame(picBtnFrame);
    pictureLayout       = new FlowLayout(pictureFrame, 16, -1, -1);
    bottomFrame         = new UkccFrame(picBtnFrame);
    bottomLayout        = new QHBoxLayout(bottomFrame);
    localBtn            = new QPushButton(bottomFrame);
    onlineBtn           = new QPushButton(bottomFrame);
    resetBtn            = new QPushButton(bottomFrame);

    screenlockLayout->setMargin(0);
    screenlockLayout->setSpacing(8);
    screenlockLayout->addWidget(wallpaperTitleLabel);
    screenlockLayout->addWidget(previewFrame);
    screenlockLayout->addWidget(centerGroup);

    //~ contents_path /Screenlock/Screenlock
    wallpaperTitleLabel->setText(tr("Screenlock"));
    previewFrame->setFixedHeight(212);
    previewLabel->setFixedSize(300, 180);
    previewLayout->addWidget(previewLabel);
    previewLayout->addStretch();

    centerGroup->addWidget(showPicWidget);
#ifdef Nile
    centerGroup->addWidget(btLeaveLockWidget);
    centerGroup->addWidget(bluetoothWidget);
    centerGroup->addWidget(noBtWidget);
    centerGroup->addWidget(setBtWidget);
#endif
    centerGroup->addWidget(picBtnFrame);

    picBtnFrame->setLineWidth(0);
    pictureFrame->setLineWidth(0);
    picBtnLayout->setMargin(0);
    picBtnLayout->setSpacing(0);
    picBtnLayout->addWidget(pictureFrame);
    picBtnLayout->addWidget(bottomFrame);

    bottomLayout->setSpacing(32);
    bottomLayout->setContentsMargins(16, 0, 16, 16);
    bottomLayout->addWidget(localBtn);
    bottomLayout->addWidget(onlineBtn);
    bottomLayout->addStretch();
    bottomLayout->addWidget(resetBtn);

    //~ contents_path /Screenlock/Local Pictures
    localBtn->setText(tr("Local Pictures"));
    //~ contents_path /Screenlock/Online Pictures
    onlineBtn->setText(tr("Online Pictures"));
    //~ contents_path /Screenlock/Reset To Default
    resetBtn->setText(tr("Reset To Default"));

    onlineBtn->setFocusPolicy(Qt::NoFocus);
    onlineBtn->setContentsMargins(0, 0, 0, 0);
    onlineBtn->setCursor(QCursor(Qt::PointingHandCursor));
    onlineBtn->setStyleSheet("QPushButton{background: transparent;border-radius: 4px;text-decoration: underline;}");
#ifdef Nile
    QIcon icon = QIcon::fromTheme("kylin-dialog-warning");
    if (icon.isNull())
        icon = QIcon::fromTheme("dialog-warning");

    setBtWidget->setIconLabel(icon);
    setBtWidget->setButtonText(tr("Bluetooth"));
    setBtWidget->setVisible(false);

    QHBoxLayout *noBtVLayout = new QHBoxLayout();
    QLabel *noBtWarnIcon = new QLabel(noBtWidget);
    QLabel *noBtMessage = new QLabel(tr("No bluetooth adapter detected, can not use Leave Lock."),noBtWidget);

    noBtWarnIcon->setPixmap(icon.pixmap(18,18));
    noBtVLayout->setContentsMargins(16, 0, 16, 0);
    noBtVLayout->setSpacing(16);
    noBtVLayout->addWidget(noBtWarnIcon);
    noBtVLayout->addWidget(noBtMessage,Qt::AlignLeft);
    noBtWidget->setLayout(noBtVLayout);
    noBtWidget->setVisible(false);

    bluetoothWidget->setVisible(false);
#endif
}

void ScreenlockUi::initRelateSet()
{
    relateTitleLabel  = new TitleLabel(this);
    relatedGroup      = new SettingGroup(this);
    monitorWidget     = new PushButtonWidget(tr("Monitor Off"), relatedGroup);
    screensaverWidget = new PushButtonWidget(tr("Screensaver"), relatedGroup);

    relateTitleLabel->setText(tr("Related Settings"));
    relateLayout->setSpacing(8);
    relateLayout->addWidget(relateTitleLabel);
    relateLayout->addWidget(relatedGroup);
    relatedGroup->addWidget(monitorWidget);
    relatedGroup->addWidget(screensaverWidget);
    monitorWidget->setButtonText(tr("Set"));
    screensaverWidget->setButtonText(tr("Set"));
}

void ScreenlockUi::initLeavLockStatus() {
    bool ispowered = isBluetoothPowered();
    bool leaveLockOn = getLeavLockOn();
    bool hasAdapter = hasBluetoothAdapter();
    QMap<QString, QString> btDevices = getBtPairedDevices();

    bluetoothWidget->comboBox()->clear();

    if (leaveLockOn)
        btLeaveLockWidget->switchButton()->click();

    canLeaveLock = !btDevices.isEmpty();
    bluetoothWidget->comboBox()->addItem(tr("Please select device"));
    for (auto dev : btDevices.keys())
        bluetoothWidget->comboBox()->addItem(btDevices.value(dev), dev);
    if (canLeaveLock && ispowered) {
        lockdev = getLeaveLockDev();
        if (!lockdev.isEmpty() && canLeaveLock) {
            bluetoothWidget->comboBox()->setCurrentIndex(bluetoothWidget->comboBox()->findData(lockdev));
        }
    }
    if (!hasAdapter && leaveLockOn) {
        noBtWidget->setVisible(!hasAdapter);
        return;
    }
    if (bluetoothWidget->comboBox()->count() == 1 && leaveLockOn) {
        setBtWidget->setVisible(true);
        noBtWidget->setVisible(false);
        bluetoothWidget->setVisible(false);
        return;
    }
    bluetoothWidget->setVisible(leaveLockOn && canLeaveLock && ispowered);
    setBtWidget->setVisible((!canLeaveLock || !ispowered) && leaveLockOn);
}

void ScreenlockUi::initSignals()
{
    connect(showPicWidget->switchButton(), &KSwitchButton::clicked, this, [=](){
        Q_EMIT showOnLoginChanged(showPicWidget->switchButton()->isChecked());
    });
#ifdef Nile
    connect(btLeaveLockWidget->switchButton(), &KSwitchButton::clicked, this, [=](bool clicked){
        if (!clicked) {
            noBtWidget->setVisible(false);
            setBtWidget->setVisible(false);
            bluetoothWidget->setVisible(false);
            if (!lockdev.isEmpty()) {
                setLeaveLock(false);
            }
            lockdev.clear();
            bluetoothWidget->comboBox()->setCurrentIndex(0);
            return;
        }

        bluetoothWidget->comboBox()->setCurrentIndex(0);
        bool ispowered = isBluetoothPowered();
        bool hasAdapter = hasBluetoothAdapter();

        if (!hasAdapter) {
            noBtWidget->setVisible(!hasAdapter);
            return;
        }
        if (bluetoothWidget->comboBox()->count() == 1) {
            setBtWidget->setVisible(true);
            noBtWidget->setVisible(false);
            bluetoothWidget->setVisible(false);
            return;
        }
        bluetoothWidget->setVisible(canLeaveLock && ispowered);
        setBtWidget->setVisible(!canLeaveLock || !ispowered);
    });

    connect(bluetoothWidget, &ComboxWidget::currentIndexChanged, this, [=](int index) {
        if (!lockdev.isEmpty()) {
            setLeaveLock(false);
        }
        if (index == 0) {
            lockdev.clear();
            return;
        }
        lockdev = bluetoothWidget->comboBox()->currentData().toString();
        setLeaveLock(true);
    });

    connect(setBtWidget, &PushButtonWidget::clicked, this, [=](){
        QProcess *process = new QProcess();
        QString cmd = "ukui-control-center";
        QStringList arg;
        arg.clear();
        arg << "-m";
        arg << "Bluetooth";
        process->startDetached(cmd,arg);
    });
#endif
    connect(monitorWidget, &PushButtonWidget::clicked, this, [=](){
        Q_EMIT toSetMonitor();
    });
    connect(screensaverWidget, &PushButtonWidget::clicked, this, [=](){
        Q_EMIT toSetScreensaver();
    });
    connect(localBtn, &QPushButton::clicked, this, [=](){
        Q_EMIT localButtonClicked();
    });
    connect(onlineBtn, &QPushButton::clicked, this, [=](){
        Q_EMIT onlineButtonClicked();
    });
    connect(resetBtn, &QPushButton::clicked, this, [=](){
        Q_EMIT resetButtonClicked();
    });
#ifdef Nile
    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                          "/com/ukui/bluetooth",
                                          "com.ukui.bluetooth",
                                          "devPairSignal",
                                          this,
                                          SLOT(addPairedDev(QString,bool)));

    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                          "/com/ukui/bluetooth",
                                          "com.ukui.bluetooth",
                                          "defaultAdapterPowerChanged",
                                          this,
                                          SLOT(powerChanged(bool)));

    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                          "/com/ukui/bluetooth",
                                          "com.ukui.bluetooth",
                                          "defaultAdapterChanged",
                                          this,
                                          SLOT(defaultAdapterChanged(QString)));

    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                          "/com/ukui/bluetooth",
                                          "com.ukui.bluetooth",
                                          "adapterAddSignal",
                                          this,
                                          SLOT(adapterAdded(QString)));

    QDBusConnection::sessionBus().connect("com.ukui.bluetooth",
                                          "/com/ukui/bluetooth",
                                          "com.ukui.bluetooth",
                                          "adapterRemoveSignal",
                                          this,
                                          SLOT(adapterRemoved(QString)));
#endif
}

void ScreenlockUi::setShowOnLogin(bool b)
{
    showPicWidget->switchButton()->blockSignals(true);
    showPicWidget->switchButton()->setChecked(b);
    showPicWidget->switchButton()->blockSignals(false);
}

void ScreenlockUi::setPicture(const QString &data)
{
    currentFile = data;
    QImageReader reader(data);
    reader.setDecideFormatFromContent(true);
    previewLabel->setPixmap(QPixmap::fromImage(reader.read()).scaled(previewLabel->size()));
    resetClickedPic();
}

void ScreenlockUi::setPictures(const QStringList &picturePathList, const QStringList &sourcePathList)
{
    if (picturePathList.size() != sourcePathList.size()) {
        qWarning()<<"picturePathList.size():"<<picturePathList.size()<<" != sourcePathList.size():"<<sourcePathList.size();
        return;
    }

    for (int i = 0; i < picturePathList.size(); ++i) {
        QPixmap pixmap;
        pixmap.load(picturePathList.at(i));
        bool clicked = false;
        if (sourcePathList.at(i) == currentFile) {
            clicked = true;
        }
        createPictureUnit(pixmap, sourcePathList.at(i), clicked);
    }
}

void ScreenlockUi::createPictureUnit(const QPixmap &pixmap, const QString &filename, const bool &clicked)
{
    PictureUnit *picUnit = new PictureUnit(this);
    picUnit->setPixmap(pixmap);
    picUnit->setFilenameText(filename);
    if (clicked) {
        prePictureUnit = picUnit;
        picUnit->changeClickedFlag(true);
        setPicture(filename);
    }
    connect(picUnit, &PictureUnit::clicked, [=](QString file){
        if (prePictureUnit) {
            prePictureUnit->changeClickedFlag(false);
        }
        prePictureUnit = picUnit;
        setPicture(file);
        Q_EMIT pictureChanged(file);
    });
    pictureLayout->addWidget(picUnit);
}

void ScreenlockUi::resetClickedPic() {
    if (prePictureUnit != nullptr) {
        prePictureUnit->changeClickedFlag(false);
        prePictureUnit = nullptr;
    }
    for (int i = pictureLayout->count() - 1; i >= 0; --i) {
        QLayoutItem *it      = pictureLayout->itemAt(i);
        PictureUnit *picUnit = static_cast<PictureUnit*>(it->widget());
        if (currentFile == picUnit->filenameText()) {
            picUnit->changeClickedFlag(true);
            prePictureUnit = picUnit;
        }
    }
}

QMap<QString, QString> ScreenlockUi::getBtPairedDevices() {
    QMap<QString, QString> pairedList;
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth",
                                                      "getPairedPhoneAddr");

    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        QStringList ret = response.arguments().takeFirst().toStringList();
        if (ret.isEmpty())
            return pairedList;
        for (int i = 0; i < ret.size(); i++) {
            if (pairedList.contains(ret.at(i)))
                continue;
            QDBusMessage _message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                                   "/com/ukui/bluetooth",
                                                                   "com.ukui.bluetooth",
                                                                   "getDevName");
            _message << ret.at(i);
            QDBusMessage _response = QDBusConnection::sessionBus().call(_message);
            if (_response.type() == QDBusMessage::ReplyMessage)
            {
                QString devName = _response.arguments().takeFirst().toString();
                if (devName == "")
                    continue;
                pairedList.insert(ret.at(i), devName);
            }
        }
    }
    return pairedList;
}

bool ScreenlockUi::hasBluetoothAdapter() {
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth", \
                                                      "getAdapterDevAddressList");

    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage) {
        QStringList ret = response.arguments().takeFirst().toStringList();
        return !ret.isEmpty();
    } else
        return false;
}

bool ScreenlockUi::isBluetoothPowered() {
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth",
                                                      "getDefaultAdapterPower");

    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage) {
        return response.arguments().takeFirst().toBool();
    } else
        return false;
}

void ScreenlockUi::addPairedDev(QString dev, bool paired) {
    int index = bluetoothWidget->comboBox()->findData(dev);
    if (paired && index >= 0)
        return;

    if (!paired && index >= 0) {
        bluetoothWidget->comboBox()->removeItem(bluetoothWidget->comboBox()->findData(dev));
        if (bluetoothWidget->comboBox()->count() == 1) {
            noBtWidget->setVisible(false);
            bluetoothWidget->setVisible(false);
            setBtWidget->setVisible(true);
        }
        if (lockdev == dev)
            lockdev.clear();
        return;
    }

    QDBusMessage _message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                           "/com/ukui/bluetooth",
                                                           "com.ukui.bluetooth",
                                                           "getDevName");
    _message << dev;
    QDBusMessage _response = QDBusConnection::sessionBus().call(_message);
    if (_response.type() == QDBusMessage::ReplyMessage)
    {
        QString devName = _response.arguments().takeFirst().toString();
        if (devName != "") {
            bluetoothWidget->comboBox()->addItem(devName, dev);
            setBtWidget->setVisible(false);
            bluetoothWidget->setVisible(true);
        }
    }
}

void ScreenlockUi::powerChanged(bool powered) {
    if (!btLeaveLockWidget->switchButton()->isChecked())
        return;
    if (!hasBluetoothAdapter()) {
        noBtWidget->setVisible(true);
        setBtWidget->setVisible(false);
        bluetoothWidget->setVisible(false);
        return;
    }

    noBtWidget->setVisible(false);
    setBtWidget->setVisible(!powered);
    bluetoothWidget->setVisible(powered);
    setLeaveLock(false);
}

void ScreenlockUi::setLeaveLock(bool on) {
    if (lockdev.isEmpty())
        return;
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth",
                                                      "setLeaveLock");
    message << lockdev << on;
    QDBusConnection::sessionBus().call(message);
}

bool ScreenlockUi::getLeavLockOn() {
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth",
                                                      "getLeaveLock");
    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage)
        return response.arguments().takeFirst().toBool();
    else
        return false;
}

QString ScreenlockUi::getLeaveLockDev() {
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth",
                                                      "getLeaveLockDev");
    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage)
        return response.arguments().takeFirst().toString();
    else
        return QString("");
}

void ScreenlockUi::defaultAdapterChanged(QString address) {
    Q_UNUSED(address);
    if (!btLeaveLockWidget->switchButton()->isChecked())
        return;
    bool ispowered = isBluetoothPowered();
    bool leaveLockOn = getLeavLockOn();
    bool hasAdapter = hasBluetoothAdapter();
    QMap<QString, QString> btDevices = getBtPairedDevices();

    lockdev.clear();
    bluetoothWidget->comboBox()->clear();

    if (leaveLockOn && !btLeaveLockWidget->switchButton()->isChecked())
        btLeaveLockWidget->switchButton()->click();

    canLeaveLock = !btDevices.isEmpty();
    bluetoothWidget->comboBox()->addItem(tr("Please select device"));
    for (auto dev : btDevices.keys())
        bluetoothWidget->comboBox()->addItem(btDevices.value(dev), dev);

    if (!hasAdapter && leaveLockOn) {
        noBtWidget->setVisible(!hasAdapter);
        return;
    }
    bluetoothWidget->setVisible(leaveLockOn && canLeaveLock && ispowered);
    setBtWidget->setVisible((!canLeaveLock || !ispowered) && leaveLockOn);
}

void ScreenlockUi::adapterAdded(QString address) {
    Q_UNUSED(address);
    if (!btLeaveLockWidget->switchButton()->isChecked())
        return;
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth", \
                                                      "getAdapterDevAddressList");

    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage) {
        QStringList ret = response.arguments().takeFirst().toStringList();
        if (ret.size() > 1)
            return;
        else {
            bool ispowered = isBluetoothPowered();
            QMap<QString, QString> btDevices = getBtPairedDevices();

            lockdev.clear();
            bluetoothWidget->comboBox()->clear();

            canLeaveLock = !btDevices.isEmpty();
            bluetoothWidget->comboBox()->addItem("请选择设备");
            for (auto dev : btDevices.keys())
                bluetoothWidget->comboBox()->addItem(btDevices.value(dev), dev);

            noBtWidget->setVisible(false);
            setBtWidget->setVisible(false);
            bluetoothWidget->setVisible(canLeaveLock && ispowered);
            setBtWidget->setVisible(!canLeaveLock || !ispowered);
        }
    }
}

void ScreenlockUi::adapterRemoved(QString address) {
    Q_UNUSED(address);
    if (!btLeaveLockWidget->switchButton()->isChecked())
        return;
    QDBusMessage message = QDBusMessage::createMethodCall("com.ukui.bluetooth",
                                                      "/com/ukui/bluetooth",
                                                      "com.ukui.bluetooth", \
                                                      "getAdapterDevAddressList");

    QDBusMessage response = QDBusConnection::sessionBus().call(message);
    if (response.type() == QDBusMessage::ReplyMessage) {
        QStringList ret = response.arguments().takeFirst().toStringList();
        if (ret.size() < 1){
            lockdev.clear();
            bluetoothWidget->comboBox()->clear();
            noBtWidget->setVisible(true);
            bluetoothWidget->setVisible(false);
            setBtWidget->setVisible(false);
        }
    }
}
