#ifndef OMOBIDISPLAYBACKEND_H
#define OMOBIDISPLAYBACKEND_H

#include <QObject>
#include <QTimer>
#include <QJsonDocument>
#include <QCryptographicHash>
#include <QSettings>
#include <QEventLoop>

#include <qbluetoothleuartclient.h>
#include <leddisplaytextmodel.h>

class LedDisplayBackend : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QBluetoothLeUartClient* bleClient READ getBleClient NOTIFY bleClientChanged)
    Q_PROPERTY(OmobiDisplayAppState state READ getState WRITE setState NOTIFY stateChanged)
    Q_PROPERTY(LedDisplayTextModel* displayTextModel READ getDisplayTextModel NOTIFY displayTextModelChanged)
    Q_PROPERTY(QVariantMap displayBrightness READ getDisplayBrightness WRITE setDisplayBrightness NOTIFY displayBrightnessChanged)
    Q_PROPERTY(float loadingProgress READ getLoadingProgress NOTIFY loadingProgressChanged)

public:
    explicit LedDisplayBackend(QObject *parent = nullptr);

    enum OmobiDisplayAppState {
        Idle,
        BluetoothOff,
        LocationPermissionDenied,
        Scanning,
        ReadyToConnect,
        Connecting,
        AuthenticationRequired,
        Authenticating,
        Initing,
        Connected,
        Loading
    };
    Q_ENUM(OmobiDisplayAppState)

    static void init() {
        qmlRegisterType<LedDisplayBackend>("de.itsblue.LedDisplayController", 1, 0, "LedDisplayBackend");
        qmlRegisterUncreatableType<LedDisplayTextModel>("de.itsblue.LedDisplayController", 1, 0, "LedDisplayTextModel", "LedDisplayTextModel cannot be created");
    };

private:
    enum OmobiDisplayCommand {
        AuthenticateCommand = 0,
        KeepAliveCommand = 1,
        GetAllTextSetsCommand = 10,
        GetTextSetParameterCommand = 11,
        GetDisplayBrightnessCommand = 12,
        SetTextSetParameterCommand = 20,
        SetDisplayBrightnessCommand = 21,
        SetDisplayCodeCommand = 22,
        SetDisplayNameCommand = 23
    };

    enum OmobiDisplayTextSetParameter
    {
        TextParameter = 0,
        ActiveParameter,
        RuntimeParameter,
        ColorParameter,
        AlignmentParameter,
        ScrollParameter,
        ScrollDirectionParameter,
        ScrollSpeedParameter,
        ScrollCountParameter,
        IndexParameter,
        DisplayTextSetParameterCount    /*!< Just for helping purposes */
    };

    enum OmobiDisplayStatusCode {
        Success = 200,
        DisplayControllerError = 501
    };

    OmobiDisplayAppState state;
    QBluetoothLeUartClient *bleClient;
    QTimer *keepAliveTimer;
    LedDisplayTextModel* displayTextModel;
    int runningCommands;
    int waitingCommands;
    float loadingProgress;

    QList<QMap<int, QVariant>> textSetsBuffer;
    QVariantMap displayBrightness;

    QSettings* settings;
    QString lastDisplaySecret;

public slots:
    Q_INVOKABLE void startScanning();
    Q_INVOKABLE void authenticate(QString secret);
    Q_INVOKABLE QBluetoothLeUartClient* getBleClient();
    Q_INVOKABLE OmobiDisplayAppState getState();
    Q_INVOKABLE LedDisplayTextModel* getDisplayTextModel();
    Q_INVOKABLE QVariantMap getDisplayBrightness();
    Q_INVOKABLE void setDisplayBrightness(QVariantMap brightness);
    Q_INVOKABLE void setDisplayCode(QString code);
    Q_INVOKABLE void setDisplayName(QString name);
    Q_INVOKABLE float getLoadingProgress();

private slots:
    void handleBluetoothStateChange(QBluetoothLeUartClient::BluetoothLeUartClientState state);
    void handleFoundNewDevice(QBluetoothLeUartDevice* device);
    void handleBluetoothDeviceConected();
    void handleBluetoothScanningError(QBluetoothLeUartClient::BluetoothScanError error);

    void handleDisplayTextModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
    void handleDisplayTextModelRowsInserted(const QModelIndex &parent, int first, int last);
    void handleDisplayTextModelRowsRemoved(const QModelIndex &parent, int first, int last);

    void sendBluetoothCommand(OmobiDisplayCommand command, QVariant data = QVariant());
    void sendBluetoothKeepAlive();
    void handleBluetoothDataReceived(QString s);
    void updateDisplayTextSetParameter(int index, int parameter);
    void updateDisplayTextSetParameter(int index, int parameter, QString value);

    void refreshLoadingState();
    void setState(OmobiDisplayAppState state);
    void setLoadingProgress(float progrss);

signals:
    void stateChanged();
    void bleClientChanged();
    void displayTextModelChanged();
    void displayBrightnessChanged();
    void commandFinished();
    void loadingProgressChanged();

};

#endif // OMOBIDISPLAYBACKEND_H
