#include "bluetoothdbus.h"
#include "config/config.h"
#include <QDBusMessage>

BluetoothDbus::BluetoothDbus(QObject *parent)
{
    Q_UNUSED(parent);
    qDebug() << Q_FUNC_INFO << __LINE__;
    connectDBusSignals();
    getDefaultAdapterPower();
    getDefaultAdapterPairedDevices();
    qDebug() << Q_FUNC_INFO << __LINE__;
}

BluetoothDbus::~BluetoothDbus()
{

}

void BluetoothDbus::connectDBusSignals() {
    qDebug() << Q_FUNC_INFO << __LINE__;
    TRANSFER_DBUS_SIGNAL("showTrayWidgetUISignal", showTrayWidgetUISignal());

    //适配器相关dbus
    CONNECT_DBUS_SIGNAL("defaultAdapterPowerChanged", defaultAdapterPowerChangedSLot(bool));
    CONNECT_DBUS_SIGNAL("defaultAdapterChanged", defaultAdapterChangedSLot(QString));
    CONNECT_DBUS_SIGNAL("adapterRemoveSignal", adapterRemoveSignalSLot(QString));
    CONNECT_DBUS_SIGNAL("adapterAddSignal", adapterAddSignalSLot(QString));
    TRANSFER_DBUS_SIGNAL("powerProgress", powerProgressSignal(bool));

    //连接、移除相关dbus
    CONNECT_DBUS_SIGNAL("devConnectStatusSignal", devConnectStatusSignalSLot(QString, bool));
    CONNECT_DBUS_SIGNAL("devNameChangedSignal", devNameChangedSignalSLot(QString, QString));
    CONNECT_DBUS_SIGNAL("devBatteryChangedSignal", devBatteryChangedSignalSLot(QString, QString));
    CONNECT_DBUS_SIGNAL("devRemoveSignal", devRemoveSignalSLot(QString));
    CONNECT_DBUS_SIGNAL("devErrorSignal", devErrorSignalSLot(QString));
    TRANSFER_DBUS_SIGNAL("ActiveConnection", activeConnectionSignal(QString,QString,QString,int,int));
    TRANSFER_DBUS_SIGNAL("devLaunchConnecting", devLaunchConnectingSignal(QString));

    //匹配相关dbus
    CONNECT_DBUS_SIGNAL("devPairSignal", devPairSignalSLot(QString, bool));
    TRANSFER_DBUS_SIGNAL("displayPasskey", displayPasskeySignal(QString,QString));
    TRANSFER_DBUS_SIGNAL("requestConfirmation", requestConfirmationSignal(QString,QString));
    TRANSFER_DBUS_SIGNAL("pairAgentCanceled", pairAgentCanceledSignal());

    //文件传输相关dbus
    CONNECT_DBUS_SIGNAL("fileReceivingSignal", receiveFilesSlot(QString,QString,QString,QString,quint64));
    TRANSFER_DBUS_SIGNAL("obexAgentCanceled", obexAgentCanceledSignal());
    TRANSFER_DBUS_SIGNAL("fileReceiveMore", fileReceiveMore(QString, quint64, QString));
    TRANSFER_DBUS_SIGNAL("sendTransferFilesMesg", sendTransferFilesMesgSignal(QStringList));
    TRANSFER_DBUS_SIGNAL("sendTransferDeviceMesg", sendTransferDeviceMesgSignal(QString));
    TRANSFER_DBUS_SIGNAL("transferredChanged", transferredChangedSignal(quint64,QString));
    TRANSFER_DBUS_SIGNAL("statusChanged", statusChangedSignal(QString,QString,QString));
    TRANSFER_DBUS_SIGNAL("initTransferPath", initTransferPathSignal(QString,bool));
    qDebug() << Q_FUNC_INFO << __LINE__;
}

void BluetoothDbus::defaultAdapterPowerChangedSLot(bool value) {
    qDebug() << Q_FUNC_INFO << __LINE__ << value;
    powered = value;
    emit powerChangedSignal(powered);
}

void BluetoothDbus::adapterRemoveSignalSLot(QString address) {
    qDebug() << Q_FUNC_INFO << __LINE__ << address;
    getTrayIconShow();
}

void BluetoothDbus::adapterAddSignalSLot(QString address) {
    qDebug() << Q_FUNC_INFO << __LINE__ << address;
    getDefaultAdapterPairedDevices();
    emit showTrayIcon(true);
    emit adapterAddSignal(address);
}

void BluetoothDbus::defaultAdapterChangedSLot(QString value) {
    qDebug() << Q_FUNC_INFO << __LINE__ << value;
    getDefaultAdapterPower();
    getDefaultAdapterPairedDevices();
    emit AdapterChangedSignal(value);
}

void BluetoothDbus::devPairSignalSLot(QString address, bool paired) {
    qDebug() << "devPairSignalSLot" << address << paired;
    if (paired && !pairedDevice.contains(address)) {
        if (!pairedList.contains(address))
            pairedList.append(address);
        addNewPairedDevice(address);
        emit sessionDevPairSignal(pairedDevice.value(address).at(0),paired);
    }
    if (!paired && pairedDevice.contains(address)) {
        QString name = pairedDevice.value(address).at(0);
        if (pairedList.contains(address))
            pairedList.removeAll(address);
        pairedDevice.remove(address);
        emit sessionDevPairSignal(name, paired);
    }
}

void BluetoothDbus::devConnectStatusSignalSLot(QString address, bool connected) {
    qDebug() << "devConnectStatusSignalSLot" << address << connected;
    if (connected
            && !connectedDevice.values().contains(address)
            && pairedDevice.keys().contains(address))
        connectedDevice.insert(pairedDevice.value(address).at(0), address);

    if (!connected
            && connectedDevice.values().contains(address)
            && pairedDevice.keys().contains(address))
        connectedDevice.remove(pairedDevice.value(address).at(0));

    emit devConnectStatusSignal(address, connected);
}

void BluetoothDbus::devNameChangedSignalSLot(QString address, QString name) {
    qDebug() << "devNameChangedSignalSLot" << address << name;
    if (!pairedDevice.contains(address))
        return;
    if (connectedDevice.values().contains(address)
            && pairedDevice.keys().contains(address)) {
        connectedDevice.remove(pairedDevice.value(address).at(0));
    }
    getDevConnectStatus(address);
    QStringList updateList;
    updateList.append(name);
    updateList.append(pairedDevice.value(address).at(1));
    updateList.append(pairedDevice.value(address).at(2));
    pairedDevice.remove(address);
    pairedDevice.insert(address, updateList);
    emit devNameChangedSignal();
}

void BluetoothDbus::devBatteryChangedSignalSLot(QString address, QString battery) {
    if (envPC == Environment::HUAWEI)
        return;
    if (!pairedDevice.contains(address))
        return;
    if (connectedDevice.values().contains(address)
            && pairedDevice.keys().contains(address)) {
        connectedDevice.remove(pairedDevice.value(address).at(0));
    }
    qDebug() << "devBatteryChangedSignalSLot" << address << battery;
    QStringList updateList;
    updateList.append(pairedDevice.value(address).at(0));
    updateList.append(pairedDevice.value(address).at(1));
    updateList.append(battery);
    pairedDevice.remove(address);
    pairedDevice.insert(address, updateList);
    emit devBatteryChangedSignal();
}

void BluetoothDbus::devRemoveSignalSLot(QString address) {
    if (pairedList.contains(address))
        pairedList.removeAll(address);
    if (pairedDevice.keys().contains(address)) {
        qDebug() << "devRemoveSignalSLot" << address;
        pairedDevice.remove(address);
        emit devRemoveSignal(address);
    }
}

void BluetoothDbus::devErrorSignalSLot(QString a) {
    qDebug() << "-----------------------" << a;
}

void BluetoothDbus::receiveFilesSlot(QString destination, QString filename, QString type, QString source, quint64 size) {
    qDebug() << Q_FUNC_INFO << __LINE__;
    if (pairedDevice.keys().contains(destination)) {
        emit receiveFilesSignal(destination,
                                pairedDevice.value(destination).at(0),
                                filename,
                                type,
                                source,
                                size);
        return;
    }
    connect(this, &BluetoothDbus::sessionDevPairSignal, this, [=](QString addr, bool paired){
        qDebug() << Q_FUNC_INFO << __LINE__;
        if (!pairedDevice.keys().contains(destination) || !paired)
            return;
        if (addr == pairedDevice.value(destination).at(0))
            receiveFilesSlot(destination, filename, type, source, size);
        disconnect(this,&BluetoothDbus::sessionDevPairSignal, this, nullptr);
    });
}

void BluetoothDbus::getTrayIconShow() {
    qDebug() << Q_FUNC_INFO << __LINE__;
    QDBusMessage _m = CREATE_METHOD_CALL("getAdapterDevAddressList");
    QDBusMessage _response1 = CALL_METHOD(_m);
    if (_response1.type() == QDBusMessage::ReplyMessage)
    {

        emit showTrayIcon(!(_response1.arguments().takeFirst().toStringList().size() == 0));
        qDebug() << Q_FUNC_INFO << __LINE__ << !(_response1.arguments().takeFirst().toStringList().size() == 0);
    }
}

void BluetoothDbus::addNewPairedDevice(QString address) {
    QStringList device;
    QDBusMessage _m1 = CREATE_METHOD_CALL("getDevName");
    _m1 << address;
    QDBusMessage _response1 = CALL_METHOD(_m1);
    if (_response1.type() == QDBusMessage::ReplyMessage)
    {
        device.append(_response1.arguments().takeFirst().toString());
    }

    QDBusMessage _m2 = CREATE_METHOD_CALL("getDevType");
    _m2 << address;
    QDBusMessage _response2 = CALL_METHOD(_m2);
    if (_response2.type() == QDBusMessage::ReplyMessage)
    {
        device.append(_response2.arguments().takeFirst().toString());
    }

    QDBusMessage _m3 = CREATE_METHOD_CALL("getDevBattery");
    _m3 << address;
    QDBusMessage _response3 = CALL_METHOD(_m3);
    if (_response3.type() == QDBusMessage::ReplyMessage)
    {
        if (envPC == Environment::HUAWEI)
            device.append(QString("-1"));
        else
            device.append(_response3.arguments().takeFirst().toString());
    }
    pairedDevice.insert(address, device);
    getDevConnectStatus(address);
}

void BluetoothDbus::sendFiles(QString address, QString filename) {
    QDBusMessage m = CREATE_METHOD_CALL("sendFiles");
    m << address << filename;

    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
    qDebug() << " sendFiles Settings succeed!";
}

void BluetoothDbus::openBluetoothSettings() {
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "openBluetoothSettings");

    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
    qDebug() << " open Bluetooth Settings succeed!";
}

void BluetoothDbus::closeSessionSignal() {
    QDBusMessage closeSig = QDBusMessage::createSignal(SYSTEMD_PATH,
                                                     SYSTEMD_INTERFACE,
                                                     "closeSessionSignal");
    QDBusConnection::sessionBus().send(closeSig);
}

void BluetoothDbus::replyRequestConfirmation(bool accept) {
    qDebug() << " reply :" << accept;

    QDBusMessage m = CREATE_METHOD_CALL("sendReplyRequestConfirmation");
    m << accept;
    qDebug() << Q_FUNC_INFO << m.arguments().at(0).value<bool>() <<__LINE__<<"QQQQ";
    // 发送Message
    QDBusMessage response = QDBusConnection::sessionBus().call(m, QDBus::NoBlock);

//    QDBusMessage displayPasskeySignal  = QDBusMessage::createSignal("/com/ukui/bluetooth",
//                                                                    "com.ukui.bluetooth",
//                                                                    "replyRequestConfirmation");
//    displayPasskeySignal << QVariant::fromValue(accept).toBool();
//    bool ret = QDBusConnection::sessionBus().send(displayPasskeySignal);
//    qDebug() << "ret--------------BluetoothDbus::replyRequestConfirmation" << ret;
}

void BluetoothDbus::continueRecieveFilesRequest() {
    qDebug() << "continue Recieve Files Request";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "sendContinueRecieveFilesSignal");
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
}

void BluetoothDbus::replyFileReceivingSignal(bool accept) {
    qDebug() << " areply :" << accept;
    QDBusMessage reply  = QDBusMessage::createSignal(SYSTEMD_PATH,
                                                     SYSTEMD_INTERFACE,
                                                     "replyFileReceivingSignal");
    reply << accept;
    bool ret = QDBusConnection::sessionBus().send(reply);
    qDebug() << "ret" << ret;
}

void BluetoothDbus::devConnect(const QString address) {
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "devConnect");
    m << address;

    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
    qDebug() << " devConnect method called succeed!";
}

void BluetoothDbus::devDisconnect(const QString address) {
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "devDisconnect");
    m << address;

    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
    qDebug() << " devDisconnect method called succeed!";
}

void BluetoothDbus::setDefaultAdapterPower(bool power) {
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "setDefaultAdapterPower");
    m << power;
    qDebug() << " setDefaultAdapterPower " << power << __LINE__;
    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
}

bool BluetoothDbus::getDevPairStatus(QString address) {
    QDBusMessage ispair = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "getDevPairStatus");
    QDBusMessage response = QDBusConnection::sessionBus().call(ispair, QDBus::NoBlock);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        qDebug() << address << " pair status : " << response.arguments().takeFirst().toBool();
        return response.arguments().takeFirst().toBool();
    } else {
        qDebug() << " getDevPairStatus method called failed!";
        return false;
    }
}

void BluetoothDbus::getDefaultAdapterPower() {
    qDebug() << "get default powered ";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "getDefaultAdapterPower");
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        powered = response.arguments().takeFirst().toBool();
        qDebug() << "init powered over : " << powered;
    } else {
        qDebug() << " powered method called failed!";
    }
}

void BluetoothDbus::getDevConnectStatus(QString address) {
    qDebug() << "get device connect status ";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "getDevConnectStatus");
    m << address;
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        bool connected = response.arguments().takeFirst().toBool();
        if (connected && pairedDevice.keys().contains(address)) {
            if (connectedDevice.values().contains(address))
                connectedDevice.remove(connectedDevice.key(address));
            connectedDevice.insert(pairedDevice.value(address).at(0), address);
        }
        if (!connected
                && connectedDevice.values().contains(address)
                && pairedDevice.keys().contains(address))
            connectedDevice.remove(pairedDevice.value(address).at(0));
        qDebug() << "init connect status : " << connected << address;
    } else {
        qDebug() << " init connect status method called failed!";
    }
}

void BluetoothDbus::cancelFileReceiving() {
    qDebug() << "cancel receiving";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "cancelFileReceiving");
    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
}

void BluetoothDbus::closeSession() {
    qDebug() << "close session";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "sendCloseSession");
    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
}

void BluetoothDbus::continueSendFiles(QString filename) {
    qDebug() << "continue send files signal";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "continueSendFiles");
    m << filename;
    QDBusConnection::sessionBus().call(m);
}

void BluetoothDbus::clearOldSession() {
    qDebug() << "clear oldsession signal";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "setclearOldSession");
    QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
}

void BluetoothDbus::replyFileReceiving(bool v) {
    qDebug() << "reply file revceive signal";
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "sendReplyFileReceivingSignal");
    m << v;
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
}

void BluetoothDbus::getDefaultAdapterPairedDevices() {
    qDebug() << "get Default Adapter Paired Devices";
    pairedList.clear();
    pairedDevice.clear();
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "getDefaultAdapterPairedDevAddress");
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        QStringList ret = response.arguments().takeFirst().toStringList();
        qDebug() << ret;
        for (int i = 0; i < ret.size(); i++) {
            if (!pairedList.contains(ret.at(i)))
                pairedList.append(ret.at(i));
            addNewPairedDevice(ret.at(i));
        }
        qDebug() << "init paired devices over : " << pairedDevice;
    } else {
        qDebug() << "value method called failed!";
    }
}

QMap<QString, QStringList> BluetoothDbus::getSendableDevices() {
    QMap<QString, QStringList> AbleDev;
    AbleDev = pairedDevice;
    for (auto item : pairedList) {
        qDebug() << "<<<<" << AbleDev;
        if(!getDevSupportFileSend(item))
            AbleDev.remove(item);
        qDebug() << "<<<< is contain" << item << AbleDev.contains(item);
    }
    qDebug() << "-----" << AbleDev;
    return AbleDev;
}

bool BluetoothDbus::getDevSupportFileSend(QString address) {
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "getDevSupportFileSend");
    m << address;
    QDBusMessage response = QDBusConnection::sessionBus().call(m);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        qDebug() << "<<______>>";
        return response.arguments().takeFirst().toBool();
    }
    return false;
}

void BluetoothDbus::activeConnectionReply(QString dev, bool v) {
    qDebug() << Q_FUNC_INFO << dev << v;
    QDBusMessage m = QDBusMessage::createMethodCall(SYSTEMD_SERVICE,
                                                    SYSTEMD_PATH,
                                                    SYSTEMD_INTERFACE,
                                                    "activeConnectionReply");
    m << dev << v;
    QDBusMessage response = QDBusConnection::sessionBus().call(m, QDBus::NoBlock);
    if (response.type() == QDBusMessage::ReplyMessage)
    {
        qDebug() << "Send Reply";
    }
}

bool BluetoothDbus::isPowered() {
    return powered;
}

QList<QString> BluetoothDbus::getPairedDevicesList() {
    return pairedList;
}

QMap<QString, QStringList> BluetoothDbus::getPairedDevices() {
    return pairedDevice;
}

bool BluetoothDbus::isConnected(QString address) {
    qDebug() << connectedDevice;
    return connectedDevice.values().contains(address);
}
