#include "aconfig.h"
#include "filesystem.h"
#include "anetwork.h"
#include "downloadmanager.h"
#include "mainwindow.h"

#include <QApplication>
#include <QtNetwork/QNetworkAccessManager>
#include <QUrl>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QObject>
#include <QEventLoop>
#include <QDir>
#include <QMap>
#include <QString>

#include <string>

ANetwork::ANetwork() {}

void ANetwork::getPatches() {
    QUrlQuery query;
    QStringList names;
    QString version;

    qInfo("%s:%i: %s", __FILE__, __LINE__, "Начинаем проверку актуальности патчей.");
    names  << "sound" << "text" << "image" << "video" << "screen" << "texture" << "font";
    QUrl url(AConfig::getInstance()->getValue("Network", "releases"));

    QString datafolder = QApplication::applicationDirPath() + "/data";

    QDir dir(datafolder);
    if(!dir.exists())
        QDir().mkdir(datafolder);

    foreach(QString s, names) {
        if(AConfig::getInstance()->getValue("Editor", s + "s") == "true"){

            if(s == "screen")
                s = "loadscreen";   // поправка для заставок

            QStringList paths = dir.entryList(QStringList(s + "*"));

            if(!paths.empty()) {
                 version = QString::number(getVersion(paths.first()));
                 QString hash = FileSystem::fileHash(datafolder + "/" + paths.first(), QCryptographicHash::Md5);
                 if(hash != AConfig::getInstance()->getValue("Hashes", s + "s")){
                     qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Эталон хэша отсутствует (удаляю файл): ", paths.first().toStdString().c_str());
                     QFile base(datafolder + "/" + paths.first());
                     base.remove();
                     version="100";
                 }

                 QString dateline = AConfig::getInstance()->getValue("Datetime", s + "s");
                 if(dateline != "-1"){
                    qDebug("%s:%i: %s", __FILE__, __LINE__, "Проставляем даты патчей.");
                    emit updatePatchDates(s, dateline.split(" ")[0]);
                 }
            } else {
                qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Патч отсутствует: ", s.toStdString().c_str());
                version = "100";
            }
            query.addQueryItem(s, version);
        }
    }

    url.setQuery(query.query());
    qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Запрашиваем информацию о патчах: ", url.fileName().toStdString().c_str());
    QString content = this->query(url);
    if(content == "error"){
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Отсутствует связь с сервером. Прервано.");
        return;
    }

    qDebug() << content;
    if(content == "") {
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Все версии патчей соответствуют актуальным.");
        return;
    }

    qInfo("%s:%i: %s", __FILE__, __LINE__, "Составляем список загрузок.");
    QStringList downloads = content.split( "|" );

    foreach (QString item, downloads) {
        QStringList values = item.split( ":::" );

        QStringList pathline = values[0].split( "_" );
        pathline = pathline[0].split( "/" );
        QUrl url = AConfig::getInstance()->getValue("Network", "server") + values[0];
        AConfig::getInstance()->setValue("Hashes", pathline[3], values[1]);
        AConfig::getInstance()->setValue("Datetime", pathline[3], values[2]);

        // Удаляем устаревшие патчи
        QStringList old = dir.entryList(QStringList(pathline[3] + "*"));
        if(old.count() > 0){
            foreach(QString filename, old){
                QFile::remove(QApplication::applicationDirPath() + "/data/" + filename);
            }
        }

        // Добавляем новый файл в список закачек
        DownloadManager::getInstance()->append(url);
    }
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Начинаем загрузку патчей.");
    DownloadManager::getInstance()->startNextDownload();
}

QString ANetwork::query(QUrl url) {
    QNetworkAccessManager* manager = new QNetworkAccessManager(MainWindow::getInstance());
    QNetworkRequest request(url);
    QNetworkReply* reply = manager->get(request);
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    QString content = reply->readAll();
    if (reply->error() != QNetworkReply::NoError){
        content = "error";
        // пишем в лог
        qDebug() << reply->errorString();
    }
    reply->deleteLater();
    return content;
}

QByteArray ANetwork::query_binary(QUrl url) {
    QNetworkAccessManager* manager = new QNetworkAccessManager(MainWindow::getInstance());
    QNetworkRequest request(url);
    QNetworkReply* reply = manager->get(request);
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();
    QByteArray bytes = reply->readAll();
    return bytes;
}

void ANetwork::getCoupon() {
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Получаем купон.");
    QString content = this->query(AConfig::getInstance()->getValue("Network", "coupon") + ".txt");
    if (content == "error")
        return;

    AConfig::getInstance()->setValue("Values", "coupon", content);
    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ",content.toStdString().c_str());
    emit getCouponFinished(content);
}

void ANetwork::getFootMessage() {
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Получаем данные для футера");
    QString content = this->query(AConfig::getInstance()->getValue("Network", "foot") + ".txt");
    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ", content.toStdString().c_str());

    if (content == "error" || content == "")
        return;

    emit getFootMessageFinished(content);
}

void ANetwork::getServers() {
    QString content = this->query(AConfig::getInstance()->getValue("Network", "servers") + ".txt");

    if (content == "error") {
        emit getServersFinished("error");
        return;
    }

    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ", content.toStdString().c_str());
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Данные получены. Производим установку значений.");
    AConfig::getInstance()->setValue("Values", "servers", content);

    emit getServersFinished(content);
}

void ANetwork::getMicroPatch(int timestamp){
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Загрузка последних обновлений");
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Уточняем наличие обновлений");

    QString microfolder = QApplication::applicationDirPath() + "/data/micro/";
    QDir dir(microfolder);
    if(!dir.exists())
        QDir().mkdir(microfolder);

    QString baseurl = AConfig::getInstance()->getValue("Network", "update");
    QString url = baseurl + "/" + QString::number(timestamp);

    qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Стартуем загрузку ", url.toStdString().c_str());
    QNetworkAccessManager m_NetworkMngr;
    QNetworkReply *reply= m_NetworkMngr.get(QNetworkRequest(url));
    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QUrl aUrl(url);
    QFileInfo fileInfo=aUrl.path();
    QString filename = microfolder + fileInfo.fileName() + ".db";
    QFile file(filename);

    file.open(QIODevice::WriteOnly);
    file.write(reply->readAll());
    delete reply;

    qInfo("%s:%i: %s", __FILE__, __LINE__, "Загрузка микропатча завершена.");

    emit getMicroPatchFinished(filename);
}

int ANetwork::getVersion(QString string) {
    std::string str(string.toLatin1().data());
    int version = 0;
    for (unsigned int i = str.find("_v") + 2; i < str.find("_v") + 7; i += 2) {
        version = version * 10 + (str[i] - '0');
    }
    return version;
}






