#ifndef INTERACTIVECAN_H
#define INTERACTIVECAN_H
#include <QObject>
#include <QtQml>

#include "../usr/CANClient.h"
#include "../usr/BluetoothClient.h"
#include "../httpclient/HttpClient.h"

typedef struct {
    int dataId;
    QString equipName;
    QString equipRfidNo;
    QString infoRfidNo;
    int target = 0;
} IsolationPointInfo;

typedef struct {
    QString keyNfc;
    QList<QString> locksNfc;
} DevicesInfoOfTask;

class InteractiveCAN : public QObject
{
    Q_OBJECT
    QML_SINGLETON
    QML_NAMED_ELEMENT(InteractiveCAN)

    Q_PROPERTY(QString cardNo READ cardNo WRITE setCardNo NOTIFY cardNoChanged)
    Q_PROPERTY(int taskCode READ taskCode WRITE setTaskCode NOTIFY taskCodeChanged)
    Q_PROPERTY(bool okOpenKey READ okOpenKey WRITE setOkOpenKey NOTIFY okOpenKeyChanged)
    Q_PROPERTY(bool okSendJobTicket READ okSendJobTicket NOTIFY okSendJobTicketChanged)
    Q_PROPERTY(bool okUnlockKey READ okUnlockKey NOTIFY okUnlockKeyChanged)
    Q_PROPERTY(bool okUnLockLocks READ okUnLockLocks NOTIFY okUnLockChanged)
public:
    static InteractiveCAN* pInstance;
    static InteractiveCAN* instance();
    static InteractiveCAN* create(QQmlEngine*, QJSEngine*);

    ~InteractiveCAN();

    QString cardNo() const {
        return m_cardNo;
    }
    void setCardNo(const QString& cardid) {
        m_cardNo = cardid;
    }

    int taskCode() const {
        return m_taskCode;
    }
    void setTaskCode(int code) {
        m_taskCode = code;
    }

    bool okOpenKey() const {
        return m_okOpenKey;
    }
    void setOkOpenKey(bool ok) {
        m_okOpenKey = ok;
        emit okOpenKeyChanged();
    }
    bool okSendJobTicket() const {
        return m_okSendJobTicket;
    }
    bool okUnlockKey() const {
        return m_okUnlockKey;
    }
    bool okUnLockLocks() const {
        return m_okUnlockLocks;
    }

    QString keyNfc() const {
        return m_keyNFC;
    }
    void setKeyNfc(const QString& nfc) {
        m_keyNFC = nfc;
    }
public:
    Q_INVOKABLE void openEKey();
    // 获取钥匙
    Q_INVOKABLE void getEKey();
    Q_INVOKABLE void getLocks();

    Q_INVOKABLE void getLockRFIDs(QMap<int, QString>& rfids);

    Q_INVOKABLE void sendJobTicket();
    // 启动检索是否自动关闭钥匙扣和锁扣
    Q_INVOKABLE void updateKeyAndLockStatus(bool status = false);

    Q_INVOKABLE void uploadColockInfo();

    Q_INVOKABLE void getWorkTicketByNodeId();

    void connectBLEDevice(const QString& keyNfc);
    void unlockDevices(const QString& nfc, const QString& deviceType);

    void resetAll();

    QString retryReadLockRFID(int lockNum);
public slots:
    void slotUnlockEKey(const CANKeyBaseChargeStatus& status);
    void slotUnlockLocks(bool success, const QList<QString>& lockRfids);
    void slotDeviceDetected(const QString& nfcId);
    void slotSearchBLE();
    void slotOkSearchedBLE(bool success);

    void slotSendJobTicketStatus(bool success);
    void slotReceivedJobTicketResult(const BLERWorkTicketResult& result);

    void checkEKeyStatus();
private:
    explicit InteractiveCAN();

    void createJobTicket();

    void createColockJobTicket();

    void httpRequestPostUploadPositionInfo(const QJsonDocument& doc);
    void httpRequestPostUpdatePointUnlock(const QJsonDocument& doc);
public:
    void httpRequestPostUploadJobTicket();
    void httpRequestPostUpdateWorkTicket();
    void httpRequestPostUpdateBackLock(const QList<QString>& lockNfcs);
    void httpRequestPostUpdateKeyBack(const QString& keyNfc, int target, const QJsonArray& lockList);
    void httpRequestGetWorkTicketByNodeId();
public slots:
    void getJobTicketInfo(quint8 nodeId, bool isLeftKey);

    void slotHttpResponseGetKeyMAC(QByteArray data);

    void slotHttpResponseGetIsolationPointInfo(QByteArray data);

    void slotHttpResponseUploadJobTicket(QByteArray data);
    void slotHttpResponseUpdateWorkTicket(QByteArray data);

    void slotHttpResponseUploadPositionInfo(QByteArray data);
    void slotHttpResponseUpdatePointUnlock(QByteArray data);
    void slotHttpResponseUpdateBackLock(QByteArray data);
    void slotHttpResponseGetWorkTicketByNodeId(QByteArray data);
    void slotHttpResponseUpdateKeyBack(QByteArray data);

    void slotUpdateColockStatus(const QString& cardNfc);

    void slotGetReturnCANDevices();
    void slotReConnectBLE();

    void slotGetPopedDevices(const QString& nfcId, const QString& deviceType, int slotIndex);
    void slotReturnKeyAndLockProcessingChanged();
signals:
    void signalReturnDevicesInfo(const QByteArray& info);
    void signalOkSearchedBLE(bool success);

    void cardNoChanged();
    void taskCodeChanged();
    void okOpenKeyChanged();
    void okSendJobTicketChanged();
    void okUnlockKeyChanged();
    void okUnLockChanged();

    void signalGetRequestData(quint64 id, QString postUrl, QByteArray data, QString token);
    void signalGetKeyMACReturnStat(int stat, const QString& msg);

    void signalGetIsolationPointInfo(quint64 id, QString postUrl, QByteArray data, QString token);

    void signalCheckedKey(quint8 nodeId, bool isLeftKey);

    void signalJobTicketResult(const QString& jsonResult, const QVariantMap& pointInfo);
    void signalJobTicketInfo(int stat, const QJsonObject& dataObj);

    void signalPostRequestData(quint64 id, QString postUrl, QByteArray data, QByteArray file, QString token);
    void signalUploadJobTicketReturnStat(int stat, QString str);
    void signalUploadPositionInfoReturnStat(int stat, QString str);

    void signalUpdateColockStatus(const QString& cardNfc);
    void signalUpdateBackLockStatus(const QList<QString>& lockNfc);
private:
    QMutex m_mutex;

    CANClient* m_canClient;
    BLEClient* m_bleClient;

    HttpClient* m_httpClient;

    QString m_keyNFC;
    QString m_currentKeyMAC;

    QTimer* m_bleConnectTimer;
    QTimer* m_checkHasKeyTimer;      // 检查是否有钥匙放入

    QJsonDocument m_ticketDoc;
    QList<int> m_isolationPoints;
    QList<IsolationPointInfo> m_pointInfo;
    QMap<int, QString> m_lockRFIDs;
    QMap<QString, QString> m_pointAndLockRfids;
    QString m_cardNo;
    int m_taskCode;

    bool m_searchedBLE = false;
    bool m_checkedFlags = true;    // 标记是否检测到钥匙放回, 防止重复
    bool m_finishedFlags = false;   // 标记一轮取锁、取钥匙完成
    bool m_startGetWorkTicketResultFlag = false;
    bool m_getLockedRfidFlag = false;

    bool m_okOpenKey = false;
    bool m_okSendJobTicket = false;
    bool m_okUnlockKey = false;
    bool m_okUnlockLocks = false;

    DevicesInfoOfTask m_currentTask;    // 当前任务所需设备
    DevicesInfoOfTask m_popedDevices;   // 已取出的设备
};

#endif // INTERACTIVECAN_H
