#ifndef QNETWORK_H
#define QNETWORK_H

#include <QNetworkReply>
#include <QJsonDocument>
#include <QEventLoop>
#include <QTimerEvent>

extern const char *const FormBoundary;

QNetworkAccessManager &netAccess();

class NetReq : public QNetworkRequest {
public:
    NetReq() {init();};
    explicit NetReq(const QString &url) : QNetworkRequest{url} {init();};
    explicit NetReq(const QUrl &url) : QNetworkRequest{url} {init();};
    NetReq(const QNetworkRequest &other) : QNetworkRequest{other} {init();};

    inline void init() {
#if(QT_VERSION_MAJOR < 6)
        setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
#endif
    }

    inline NetReq &type(const QByteArray &value) {
        setRawHeader("Content-Type", value);
        return *this;
    }
    inline NetReq &typeJson() {
        setRawHeader("Content-Type", "application/json");
        return *this;
    }
    inline NetReq &timeout(int timeout) {
        setTransferTimeout(timeout);
        return *this;
    }

    inline QNetworkReply *get() {
        return netAccess().get(*this);
    }
    inline QNetworkReply *post(const QByteArray &data) {
        return netAccess().post(*this, data);
    }
    inline QNetworkReply *post(const QJsonDocument &json) {
        setRawHeader("Content-Type", "application/json");
        return netAccess().post(*this, json.toJson(QJsonDocument::Compact));
    }
    inline QNetworkReply *post(const QJsonObject &json) {
        return post(QJsonDocument{json});
    }
    inline QNetworkReply *post(const QJsonArray &json) {
        return post(QJsonDocument{json});
    }
    inline QNetworkReply *post(QHttpMultiPart *multiPart) {
        return netAccess().post(*this, multiPart);
    }
};

QString errStr(QNetworkReply *);
QString errStrWithData(QNetworkReply *, QJsonDocument * = 0);

inline void abortSilence(QNetworkReply *reply) {
    reply->blockSignals(true);
    reply->abort();
    reply->blockSignals(false);
    reply->deleteLater();
}

const char* socketErrKey(int value);

class TcpSocket : public QTcpSocket {
    Q_OBJECT
public:
    explicit TcpSocket(QObject *parent = nullptr) : QTcpSocket{parent} {};
    ~TcpSocket() {
        if(timerId!=0) killTimer(timerId);
    };
    bool waitForConnected(int msecs = 30000) override;
    bool waitForDisconnected(int msecs = 30000) override;
    bool waitForBytesWritten(int msecs = 30000) override;
    bool waitForReadyRead(int msecs = 30000) override;
protected:
    void timerEvent(QTimerEvent *e) override {
        if(e->timerId()!=timerId) return;
        killTimer(timerId);
        timerId = 0;
        emit timeout(5);
    };
    bool connAndExec(int msecs, QEventLoop *loop);
    inline void timerStop() {
        if(timerId==0) return;
        killTimer(timerId);
        timerId = 0;
    }
    int timerId = 0;
signals:
    void timeout(int);
};

#endif // QNETWORK_H