#include <QtGlobal>
#include <QCoreApplication>
#include <QByteArray>

#include <QProcess>
#include <QCommandLineParser>
#include <QStandardPaths>
#include <QSettings>
#include <QDir>
#include <QDebug>

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QRegularExpression>
#include <QFile>
#include <QTextStream>
#include <QDateTime>

#include <optional>

#include "message_handler.h"
#include "utils_internal.h"
#include "ismas_client.h"


int main(int argc, char **argv) {
    QByteArray const value = qgetenv("LC_ALL");
    if (value.isEmpty() || value != "C") {
        qputenv("LC_ALL", "C");
    }

    openlog("ATB-UPDATE_CHECK", LOG_PERROR | LOG_PID | LOG_CONS, LOG_USER);

    QCoreApplication a(argc, argv);
    QCoreApplication::setApplicationName("ATBUpdateCheck");
    QCoreApplication::setApplicationVersion(APP_VERSION);

    if (!messageHandlerInstalled()) { // change internal qt-QDebug-handling
        atbInstallMessageHandler(nullptr);
        //atbInstallMessageHandler(atbDebugOutput);
        setDebugLevel(LOG_NOTICE);
    }

    int exitCode = 0;
    QCommandLineParser parser;
    QCommandLineOption ismasConnectOption("ismas-connected");
    QCommandLineOption updateRequestedOption("update-requested");
    QCommandLineOption verboseOption("verbose");
    parser.addOption(ismasConnectOption);
    parser.addOption(updateRequestedOption);
    parser.addOption(verboseOption);
    parser.process(a);

    QString connectionStatus{internal::ISMAS_NOT_CONNECTED};
    QString updateRequestStatus{internal::UPDATE_NOT_REQUESTED};
    QDebug debug = qCritical();

    if (std::optional<QString> result
            = IsmasClient::sendRequestReceiveResponse(
                IsmasClient::APISM::DIRECT_PORT,
                "#M=APISM#C=REQ_SELF#J={}")) {
        QJsonDocument d = QJsonDocument::fromJson(result.value().toUtf8());
        for (QString const &k : d.object().keys()) {
            if (k.contains("CMD_GET_APISMSTATUS_RESPONSE")) {
                QJsonObject o = d.object()[k].toObject();
                QJsonObject::const_iterator it = o.find("Broker");
                if (it != o.constEnd()) {
                    // value for "Broker"
                    QString const &v = it->toString();
                    if (v.contains(internal::ISMAS_CONNECTED, Qt::CaseInsensitive)) {
                        connectionStatus = internal::ISMAS_CONNECTED;
                    } else
                    if (v.contains(internal::ISMAS_NOT_CONNECTED, Qt::CaseInsensitive)) {
                        connectionStatus = internal::ISMAS_NOT_CONNECTED;
                    } else
                    if (v.contains(internal::ISMAS_DISCONNECTED, Qt::CaseInsensitive)) {
                        connectionStatus = internal::ISMAS_NOT_CONNECTED;
                    } else
                    if (v.contains(internal::ISMAS_CONNECTION_IN_PROGRESS, Qt::CaseInsensitive)) {
                        connectionStatus = internal::ISMAS_NOT_CONNECTED;
                    } else
                    if (v.contains(internal::ISMAS_DISCONNECTING, Qt::CaseInsensitive)) {
                        connectionStatus = internal::ISMAS_NOT_CONNECTED;
                    }
                    break;
                }
            }
        }
    }

    if (connectionStatus != internal::ISMAS_CONNECTED) {
        if (internal::customerRepoExists() == false) {
            debug.noquote() << internal::NO_CUSTOMER_REPOSITORY;
        }
    }

    if (parser.isSet(updateRequestedOption)) {
        if (internal::customerRepoExists() == false) {
            // if the customer repository does not exists, it does not matter is
            // ISMAS is connected or how the setting for the WAIT-button is.
            updateRequestStatus = internal::NO_CUSTOMER_REPOSITORY;
        } else {
            if (connectionStatus == internal::ISMAS_CONNECTED) {
                if (std::optional<QString> result
                        = IsmasClient::sendRequestReceiveResponse(
                            IsmasClient::APISM::DIRECT_PORT,
                            "#M=APISM#C=REQ_ISMASPARAMETER#J={}")) {

                    QJsonDocument d = QJsonDocument::fromJson(result.value().toUtf8());
                    for (QString const &k : d.object().keys()) {
                        if (k.contains("REQ_ISMASPARAMETER")) {
                            QJsonObject o = d.object()[k].toObject();

                            QJsonObject::const_iterator it = o.find("Aknoledge");
                            if (it == o.constEnd()) continue;

                            QString const &v = it->toString();
                            if (v != "OK") break;

                            for (QString const &m : d.object().keys()) { // request ack
                                if (!m.contains("FileUpload", Qt::CaseInsensitive)) continue;
                                QJsonObject o2 = d.object()[m].toObject();

                                QJsonObject::const_iterator it2 = o2.find("TRG");
                                if (it2 == o2.constEnd()) break;

                                QString const &v2 = it2->toString();
                                if (v2 == "WAIT") {
                                    updateRequestStatus = internal::UPDATE_REQUESTED;
                                } else {
                                    // the customer-repository does exist, and the ISMAS-trigger is
                                    // *NOT* "WAIT", but from 00:00:00 - 00:03:59 this counts as an
                                    // automatic update
                                    QDateTime const &current = QDateTime::currentDateTime();
                                    if (current.time().hour() < 4) {
                                        updateRequestStatus = internal::UPDATE_NOT_NECESSARY;
                                    } else {
                                        updateRequestStatus = internal::UPDATE_NOT_REQUESTED;
                                        exitCode = -2;
                                    }
                                }
                                break;
                            }
                            break;
                        }
                    }
                }
            } else {
                // not connected (so its unknown if update has been requested),
                // and customer repository exists. Assume 'not requested'.
                updateRequestStatus = internal::UPDATE_NOT_REQUESTED;
                exitCode = -1;
            }
        }
        debug.noquote() << updateRequestStatus;
    } else
    if (parser.isSet(ismasConnectOption)) {
        debug.noquote() << connectionStatus;
    }

    return exitCode;
}