#ifndef ISMAS_CLIENT_H_INCLUDED
#define ISMAS_CLIENT_H_INCLUDED

#include <QObject>
#include <QString>

#include <optional>

struct PSAInstalled {
    struct VersionInfo {
        QString created;
        QString reason;
        QString lastCommit;
    } versionInfo;

    struct Tariff {
        QString name;
        QString version;
        QString project;
        int zone;
        int size;
        QString blob;
        QString lastCommit;
        QString info;
        QString loadTime;
    } tariff;

    struct HardWare {
        QString linuxVersion;
        QString cpuSerial;
    } hw;

    struct Opkg {
        int size;
        QString blob;
        QString lastCommit;
        QString loadTime;
    } opkg;

    struct DC {
        QString versionHW;
        QString versionSW;
        QString gitBlob;
        QString gitLastCommit;
        int size;
    } dc;

    struct SoftWare {
        QString apismVersion;
        QString atbQTVersion;
    } sw;

    struct PluginVersion {
        QString deviceController;
        QString ingenicoISelfCC;
        QString mobilisisCalculatePrice;
        QString mobilisisCalculatePriceConfigUi;
        QString prmCalculatePrice;
        QString prmCalculatePriceConfigUi;
        QString tcpZVT;
    } pluginVersion;

    struct DC2C {
        QString name;
        QString blob;
        int size;
    };

    DC2C cash;
    DC2C conf;
    DC2C device;

    DC2C print[32];

    explicit PSAInstalled() {
        tariff.name = "N/A";
        tariff.version = "N/A";
        tariff.project = "N/A";
        tariff.zone = -1;
        tariff.size = -1;
        tariff.blob = "N/A";
        tariff.info = "N/A";
        tariff.loadTime = "N/A";

        hw.linuxVersion = "N/A";
        hw.cpuSerial = "N/A";

        opkg.size = -1;
        opkg.blob = "N/A";
        opkg.lastCommit = "N/A";
        opkg.loadTime = "N/A";

        dc.versionHW = "N/A";
        dc.versionSW = "N/A";
        dc.gitBlob = "N/A";
        dc.gitLastCommit = "N/A";
        dc.size = -1;

        sw.apismVersion = "N/A";
        sw.atbQTVersion = "N/A";

        pluginVersion.deviceController = "N/A";
        pluginVersion.ingenicoISelfCC = "N/A";
        pluginVersion.mobilisisCalculatePrice = "N/A";
        pluginVersion.mobilisisCalculatePriceConfigUi = "N/A";
        pluginVersion.prmCalculatePrice = "N/A";
        pluginVersion.prmCalculatePriceConfigUi = "N/A";
        pluginVersion.tcpZVT = "N/A";

        cash.name = "N/A";
        cash.blob = "N/A";
        cash.size = -1;

        conf.name = "N/A";
        conf.blob = "N/A";
        conf.size = -1;

        device.size = -1;
        device.blob = "N/A";
        device.size = -1;

        for (int i=0; i < 32; ++i) {
            print[i].size = -1;
            print[i].blob = "N/A";
            print[i].size = -1;
        }
    }
};

class IsmasClient : public QObject {
    Q_OBJECT

    int m_progressInPercent;
public:
    explicit IsmasClient() : m_progressInPercent(1) {}

    enum APISM {
        DB_PORT = 7777,
        DIRECT_PORT = 7778
    };


    enum RESULT_CODE {
        SUCCESS=0,
        NO_UPDATE_NECESSARY=1,
        BACKUP_FAILED=2,
        WRONG_PACKAGE=3,
        INSTALL_ERROR=4};

    enum REASON {
        TIME_TRIGGERED = 0,
        SERVICE,
        DEV_TEST,
        ENTRIES
    };

    static char const *reason[REASON::ENTRIES];

    static std::optional<QString>
        sendRequestReceiveResponse(int port, QString const &request);

    static QString getReasonForLastSendVersion();

    int getProgressInPercent() const {return m_progressInPercent; }
    void setProgressInPercent(int procent) { m_progressInPercent = procent; }

    QString updateNewsToIsmas(char const *event,
                              int percent,
                              int resultCode,
                              char const *step,
                              char const *step_result,
                              char const *version);

    QString updateOfPSAStarted(QString const &version = QString());   // start of update process
    QString cloneAndCheckoutCustomerRepository(QString const &info, QString const &version = QString());   // clone and checkout customer repository
    QString checkoutBranch(QString const &info, QString const &version = QString());   // checkout branch
    QString errorBackendNotConnected(QString const &info, QString const &version = QString());   // checkout branch
    QString errorGitClone(int percent, QString const &info, QString const &version = QString());
    QString backendConnected(QString const &info, QString const &version = QString());
    QString updateTriggerSet(QString const &info, QString const &version = QString());
    QString errorUpdateTrigger(QString const &info, QString const &version = QString());
    QString gitFetch(QString const &info, QString const &version = QString());
    QString execOpkgCommand(QString const &info, QString const &version = QString());
    QString rsyncFile(QString const &info, QString const &version = QString());
    QString errorGitFetch(int resultCode, QString const &info, QString const &version = QString());
    QString updateOfPSAActivated(QString const &version = QString());
                                    // and update accepted
    QString updateOfPSASucceeded(QString const &version = QString()); // update process succeeded
    QString updateOfPSAContinues(QString currentStage, QString currentStageInfo, QString const &version = QString());
    QString updateOfPSAFailed(int resultCode, QString step, QString reason, QString const &version = QString());
    QString sanityCheckFailed(int resultCode, QString reason, QString const &version = QString());
    QString jsonParseFailed(int resultCode, QString reason, QString const &version = QString());
    std::optional<QString> finalResult(int resultCode, QString reason, QString const &version = QString());

    QString updateOfPSASendVersion(PSAInstalled const &psa);

  private:
    static void printDebugMessage(int port, QString const &clientIP, int clientPort,
                                  QString const &message);
    static void printInfoMessage(int port, QString const &clientIP, int clientPort,
                                 QString const &message);
    static void printErrorMessage(int port, QString const &clientIP, int clientPort,
                                  QString const &message);
};

#endif // ISMAS_CLIENT_H_INCLUDED
