#include "QtHttps.h"
#include "LightLog.h"

#include <QEventLoop>
// #include "spdlog/spdlog.h"

QtHttps::QtHttps(QObject *parent) :
    QObject(parent)
{
    /* 初始化函数 */
    m_manager = new QNetworkAccessManager(this);
    /* 设置定时器精度 */
    m_timer.setTimerType(Qt::PreciseTimer);
    m_timer.setSingleShot(true);

    /* 检查是否支持OpenSSL */
    bool isSupport = QSslSocket::supportsSsl();
    QString opensslVersion = QSslSocket::sslLibraryVersionString();
    QString openSSLBuildVersion = QSslSocket::sslLibraryBuildVersionString();
    QLOG_INFO("OpenSSL is support : " + QString::number(isSupport));
    // QLOG_INFO("OpenSSL version : " + opensslVersion);
    // QLOG_INFO("OpenSSL build version : " + openSSLBuildVersion);
    /* 查看支持的协议 */
    auto list = m_manager->supportedSchemes();
    QString str;
    for(auto &item : list)
    {
        str = str + item + " ";
    }
    QLOG_INFO("supportedSchemes : " + str);

    /* 连接信号和槽 */
    connect(&m_timer, &QTimer::timeout, this, &QtHttps::do_timeout);

}
QtHttps::~QtHttps()
{
    delete m_manager;
    if(m_file != nullptr)
    {
        if(m_file->isOpen())
        {
            m_file->close();
        }
        delete m_file;
        m_file = nullptr;
    }
    if(m_reply != nullptr)
    {
        m_reply->deleteLater();
        m_reply = nullptr;
    }
}

bool QtHttps::Get(const QString &url)
{
    if(m_manager == nullptr)
    {
        QLOG_WARN("m_manager is nullptr");
        return false;
    }
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    /* 等待返回 */
    
    m_reply = m_manager->get(request);
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::do_replyFinished);
    connect(m_reply, &QNetworkReply::readyRead, this, &QtHttps::do_replyReadyRead);
    connect(m_reply, &QNetworkReply::downloadProgress, this, &QtHttps::do_downloadProgress);
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    connect(m_reply, &QNetworkReply::errorOccurred, this, &QtHttps::do_error);
    #endif

    /* 转发信号 */
    connect(m_reply, &QNetworkReply::downloadProgress, this, &QtHttps::signal_downloadProgress);
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::signal_replyFinished);

    m_isFinished = false;
    return true;
}

/* 获取请求头信息 */
bool QtHttps::GetHead(const QString &url)
{
    if(m_manager == nullptr)
    {
        QLOG_WARN("m_manager is nullptr");
        return false;
    }
    QNetworkRequest request;


    // QSslConfiguration conf = request.sslConfiguration();
    // conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    // conf.setProtocol(QSsl::TlsV1SslV3);
    // request.setSslConfiguration(conf);

    request.setUrl(url);


    m_reply = m_manager->head(request);
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::do_replyFinished);
    connect(m_reply, &QNetworkReply::readyRead, this, &QtHttps::do_replyReadyRead);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    connect(m_reply, &QNetworkReply::errorOccurred, this, &QtHttps::do_error);
#endif

    /* 转发信号 */
    connect(m_reply, &QNetworkReply::downloadProgress, this, &QtHttps::signal_downloadProgress);
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::signal_replyFinished);

    m_isFinished = false;
    return true;
}

void QtHttps::Post(const QString &url, const QByteArray &data)
{

}


/* 下载文件 */
void QtHttps::downloadFile(const QString &url, const QString &filePath)
{
    if(m_manager == nullptr)
    {
        QLOG_WARN("m_manager is nullptr");
        return;
    }
    /* 检查文件有效性 */
    m_file = new QFile(this);
    m_file->setFileName(filePath);
    if(!m_file->open(QIODevice::WriteOnly | QIODevice::Truncate))
    {
        QLOG_WARN("open file failed , file path : " + filePath);
        m_file->close();
        delete m_file;
        m_file = nullptr;
        return;
    }
    /* 发送请求 */
    QNetworkRequest request;
    request.setUrl(QUrl(url));
    m_reply = m_manager->get(request);
    /* 链接信号和槽 */
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::do_replyFinished);
    connect(m_reply, &QNetworkReply::readyRead, this, &QtHttps::do_replyReadyRead);
    connect(m_reply, &QNetworkReply::downloadProgress, this, &QtHttps::do_downloadProgress);
    #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
    connect(m_reply, &QNetworkReply::errorOccurred, this, &QtHttps::do_error);
    #endif

    /* 转发信号 */
    connect(m_reply, &QNetworkReply::downloadProgress, this, &QtHttps::signal_downloadProgress);
    connect(m_reply, &QNetworkReply::finished, this, &QtHttps::signal_replyFinished);

    m_isFinished = false;
}


/**
 * @brief 等待完成,同时设置超时时间,超时后,断开reply的信号和槽的连接
 *        参数设置为0表示查询是否完成,设置为-1表示一直等待
 * 
 * @param msecs 超时时间
 *  @arg -1 一直等待,将会阻塞在这里
 *  @arg 0 查询是否完成
 *  @arg 正整数,等待完成的时间,设置完成之后再次设置,会覆盖之前的设置
 * @return true 
 * @return false 
 */
bool QtHttps::waitFinished(int msecs)
{
    if(msecs == 0)
    {
        return m_isFinished;
    }
    else if(msecs == -1)
    {
        QEventLoop loop;
        connect(this, &QtHttps::signal_replyFinished, &loop, &QEventLoop::quit);
        loop.exec();
        return true;
    }
    else if (msecs > 0)
    {
        m_timer.start(msecs);
        return m_isFinished;
    }
    return m_isFinished;
}


/* 请求完成的槽函数 */
void QtHttps::do_replyFinished()
{
    QLOG_DEBUG("do_replyFinished");
    /* 停止定时器 */
    if(m_timer.isActive())
    {
        m_timer.stop();
    }
    /* 获取状态码 */
    auto retCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
    if(m_reply->error() == QNetworkReply::NoError)
    {
        QLOG_DEBUG("reply : " + QString::number(retCode));
        auto list = m_reply->rawHeaderList();
        for(auto &item : list)
        {
            // SPDQLOG_INFO("{} : {}", item.toStdString(), m_reply->rawHeader(item).toStdString());
            QLOG_DEBUG(item + " : " + m_reply->rawHeader(item));
        }
        /* 检查文件是否打开 */
        if(m_file != nullptr)
        {
            if(m_file->isOpen())
            {
                m_file->close();
            }
            delete m_file;
            m_file = nullptr;
        }
    }
    else
    {
        QLOG_WARN("reply error : " + QString::number(retCode) + " " + m_reply->errorString());
    }
    /* 检查文件是否打开 */
    if(m_file != nullptr)
    {
        if(m_file->isOpen())
        {
            m_file->close();
        }
        delete m_file;
        m_file = nullptr;
    }
    /* 记得设置这个,需要手动释放 */
    m_reply->deleteLater();
    m_reply = nullptr;
    /* 设置完成标志 */
    m_isFinished = true;
}

/* 读取数据 */
void QtHttps::do_replyReadyRead()
{
    // QLOG_DEBUG("do_replyReadyRead");
    if(m_file != nullptr)
    {
        m_file->write(m_reply->readAll());
    }
}

/* 下载进度 */
void QtHttps::do_downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    // QLOG_DEBUG("do_downloadProgress");
    QLOG_DEBUG("bytesReceived / bytesTotal : " + QString::number(bytesReceived) + " / " + QString::number(bytesTotal));
}

#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
void QtHttps::do_error(QNetworkReply::NetworkError code)
{
    QLOG_WARN("error : " + QString::number(code));
}
#endif


/* 超时,断开reply连接,删除reply */
void QtHttps::do_timeout()
{
    QLOG_WARN("Http timeout");
    if(m_reply != nullptr)
    {
        m_reply->disconnect();
        m_reply->abort();
        m_reply->deleteLater();
        m_reply = nullptr;
    }
    m_isFinished = true;
}