#include "app.h"
#include "filesystem.h"
#include "lotromanager.h"

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

ANetwork::ANetwork() {

}

ANetwork::ANetwork(const ANetwork&) {
    throw QException(); // Выкидываем QException, в случае если
                        // вообще попытались скопировать объект
}

ANetwork& ANetwork::operator=(ANetwork&) {
    throw QException(); // Выкидываем QException, в случае если
                        // вообще попытались скопировать объект
}

QString ANetwork::query(QUrl url){
    App *app = &App::getInstance();
    QNetworkAccessManager* manager = new QNetworkAccessManager(app->window);
    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){
    App *app = &App::getInstance();
    QNetworkAccessManager* manager = new QNetworkAccessManager(app->window);
    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;
}

QString ANetwork::getCoupon(){
    App *app = &App::getInstance();
    app->logSectionStart("Код купона");
    QString content = this->query(app->config->getValue("Network", "coupon") + ".txt");
    if (content != "error"){
        app->config->setValue("Values", "coupon", content);
        qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ", content.toLocal8Bit().data());
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Данные получены. Производим установку значений.");
    } else {
        qWarning("%s:%i: %s", __FILE__, __LINE__, "Не удалось получить информацию с сервера");
        content = app->config->getValue("Values", "coupon");
    }
    app->window->ui->couponButton->setText(content);
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
    app->logSectionEnd();
    return content;
}

QString ANetwork::getFootMessage(){
    App *app = &App::getInstance();
    app->logSectionStart("Информация о профилактике");
   // app->window->ui->footRed->setText("Профилактика. Все сервера отключены. Примерное время окончания работ - 40:00 (МСК).");
    QString content = this->query(app->config->getValue("Network", "foot") + ".txt");
    if (content != "error"){
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Данные получены");
        app->config->setValue("Values", "foot", content);
        qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ", content.toLocal8Bit().data());
    } else {
        qWarning("%s:%i: %s", __FILE__, __LINE__, "Не удалось получить информацию с сервера");
        content = app->config->getValue("Values", "foot");
        app->logSectionEnd();
        return content;
    }

    if(content != ""){
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Есть сообщения о профилактике. Производим разбор и установку значений");
        QStringList list = content.split(":::");
        //QStringList date = list[2].split(" ");

        QString day = list[2];
        QString month = " " + list[3];
        app->window->ui->footYellow->show();
        app->window->ui->footYellow->setText("Профилактика игровых серверов состоится " + day + month + " с " + list[0] +" до " + list[1] + " (МСК).");
    } else {
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Сообщения о профилактике отсутствуют.");
    }
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
    app->logSectionEnd();
    return content;
}


QString ANetwork::getServers(){
    App *app = &App::getInstance();
    QString time = "";
    app->logSectionStart("Статусы серверов");
    QString content = this->query(app->config->getValue("Network", "servers") + ".txt");
    if (content != "error"){
        qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Ответ сервера: ", content.toLocal8Bit().data());
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Данные получены. Производим установку значений.");
        app->config->setValue("Values", "servers", content);
        qDebug() << content;
    } else {
        qWarning("%s:%i: %s", __FILE__, __LINE__, "Не удалось получить информацию с сервера.");
        content = app->config->getValue("Values", "servers");
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
        app->logSectionEnd();
        return content;
    }

    if(content == "profilaktika"){
        qInfo("%s:%i: %s", __FILE__, __LINE__, "По данным сервера в данный момент идут техработы.");
        foreach(QObject * obj,  app->window->ui->serversbox->children()){
            if (obj != nullptr && obj->objectName() != ""){
                QLabel * label = dynamic_cast<QLabel*>(obj);
                label->setStyleSheet("QLabel{ background-color:#8A0808; }");
             }
        }

        qInfo("%s:%i: %s", __FILE__, __LINE__, "Парсим данные о профилактике.");
        content = app->config->getValue("Values", "foot");
        if(content != ""){
            QStringList list = content.split(":::");
            time = "Примерное время окончания работ - " + list[1] + " (МСК)";
        }

        qInfo("%s:%i: %s", __FILE__, __LINE__, "Выводим сообщение о профилактике.");
        app->window->ui->footRed->show();
        app->window->ui->footRed->setText("Профилактика. Все сервера отключены. " + time);
        if(app->window->ui->footYellow->text() != "") app->window->ui->footYellow->setText("");
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
        app->logSectionEnd();


        return content;
    }

    qInfo("%s:%i: %s", __FILE__, __LINE__, "Раскрашиваем индикаторы серверов.");
    QStringList data = content.split("|||");
    foreach(QString item, data){
        QStringList server = item.split(":::");
        QString color = server[1] == "on" ? "#173B0B" : "#8A0808";
        QLabel* obj = app->window->ui->serversbox->findChild<QLabel*>(server[0]);
        if (obj != nullptr){
            obj->setStyleSheet("QLabel{ background-color:" + color + "; }");
        }
    }
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
    app->logSectionEnd();
    return content;
}


void ANetwork::getPaths(){
    App *app = &App::getInstance();
    QUrlQuery query;
    QStringList names;
    QString version;
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Начинаем проверку актуальности патчей.");
    names  << "sound" << "text" << "image" << "video" << "screen" << "texture" << "font";
    QUrl url(app->config->getValue("Network", "releases"));

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

    foreach(QString s, names){
        if(app->config->getValue("Editor", s + "s") == "true"){
            if(s == "screen") s = "loadscreen";// поправка для заставок

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

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

                 QString dateline = app->config->getValue("Datetime", s + "s");
                 if(dateline != "-1"){
                    qDebug("%s:%i: %s", __FILE__, __LINE__, "Проставляем даты патчей.");
                    QLabel* obj = app->window->ui->mainbox->findChild<QLabel*>(s + "sStatus");
                    if (obj != nullptr){
                        QStringList date = dateline.split(" ");
                        obj->setText(date[0]);
                    }

                 }

            } else {
                qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Патч отсутствует: ", s.toLocal8Bit().data());
                version = "100";
                QLabel* obj = app->window->ui->mainbox->findChild<QLabel*>(s + "sStatus");
                if (obj != nullptr) {
                    obj->setText("Оригинал");
                }

            }
            query.addQueryItem(s, version);
        }
    }

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

    qDebug() << content;
    if(content == "") {
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Все версии патчей соответствуют актуальным.");
        app->helper->setState("busy");
        LotroManager::getInstance().applyGlobal();
        app->helper->setState("free");
        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 = values[0];
        app->config->setValue("Hashes", pathline[3], values[1]);
        app->config->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);
            }
        }

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

QString ANetwork::getMicroPath(int timestamp){

    App *app = &App::getInstance();

    app->logSectionStart("Загрузка последних обновлений");
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Уточняем наличие обновлений");

    QString microfolder = QApplication::applicationDirPath() + "/data/micro/";
    QDir dir(microfolder);
    if(!dir.exists()) QDir().mkdir(microfolder);
    QString baseurl = app->config->getValue("Network", "update");
    QString url = baseurl + "/1/" + 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 = micropatch;
    QFile file(filename);
    file.open(QIODevice::WriteOnly);
    file.write(reply->readAll());
    delete reply;
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Загрузка микропатча завершена.");


    LotroManager::getInstance().database_.InitDatabase(filename.toLocal8Bit().data());
    int indb = LotroManager::getInstance().database_.CountRows();
    qInfo("%s:%i: %s%i", __FILE__, __LINE__, "Патч содержит строк: ", indb);
    for(int i = 0; i<=indb; i++) LotroManager::getInstance().processFile();
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
    LotroManager::getInstance().saveDatFiles();
    LotroManager::getInstance().database_.CloseDatabase();
    app->logSectionEnd();

    return filename;

}










