/*
 * This file contains minor utility functions
 */

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>
#include <QFile>
#include <QTimer>
#include <QLockFile>
#include <QDir>
#include <QMessageBox>

#include "models/settings.h"
#include "utils.h"

bool checkInternetConnection(QUrl url) {
    QNetworkAccessManager nam;
    QNetworkRequest req(url);
    QNetworkReply* reply = nam.get(req);
    QEventLoop loop;
    QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);

    QTimer request_timeout_timer;
    QObject::connect(&request_timeout_timer, &QTimer::timeout, &loop, &QEventLoop::quit);
    request_timeout_timer.start(5000); // 5 seconds connection timeout
    loop.exec();
    return reply->bytesAvailable();
}

void logMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QString message_type;

    switch (type) {
    case QtDebugMsg:
        message_type = "[DEBG]";
        break;
    case QtInfoMsg:
        message_type = "[INFO]";
        break;
    case QtWarningMsg:
        message_type = "[WARN]";
        break;
    case QtCriticalMsg:
        message_type = "[CRIT]";
        break;
    case QtFatalMsg:
        message_type = "[FATL]";
        break;
    default:
        message_type = "[UNKN]";
        break;
    }

    QString filename = context.category;
    QString function = context.function;
    QString line_number = QString::number(context.line);

    QString s = QString("%1: %2 ||| %3:%4 %5\n")
                .arg(message_type)
                .arg(msg)
                .arg(filename)
                .arg(line_number)
                .arg(function);

#ifdef QT_DEBUG
    QFile log_file("legacy_v2.log");
    log_file.open(QIODevice::ReadWrite | QIODevice::Append);
    QTextStream stream(&log_file);
    stream << s;
    log_file.close();
#endif

    fprintf(stderr, "%s", qUtf8Printable(s));
    fflush(stderr);
}

bool checkSingleAppInstance() {
    QLockFile lockFile(QDir::temp().absoluteFilePath("rulotro.lock"));
    if(!lockFile.tryLock(1)){
        qDebug() << "Lock file already exists! Some other application is already running...";
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.setText("Приложение уже запущено.\nРазрешено запускать только один экземпляр приложения.");
        msgBox.exec();
        return false;
    }
    return true;
}

AppErrorStatus CheckAppPrerequesities() {
    size_t status = E_NO_ERRORS;
    QString game_folder_path = Settings::getValue("Lotro/game_path").toString();
    QString locale_prefix = Settings::getValue("Lotro/original_locale").toString();

    // Checking LotroLauncher.exe availability
    QFileInfo lotro_launcher_exe(game_folder_path + "/LotroLauncher.exe");
    if (!lotro_launcher_exe.exists()) {
        status |= E_WRONG_GAME_FOLDER;
    } else {
        if (!QFile::setPermissions(lotro_launcher_exe.absoluteFilePath(),
                QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ExeUser)) {
            status |= E_WRONG_FILE_PERMISSIONS;
        }
    }

    // Checking DAT files availability & correctness
    QString client_local_filepath = game_folder_path + "/client_local_" + locale_prefix + ".dat";
    QString client_general_filepath = game_folder_path + "/client_general.dat";

    QFileInfo client_local_file(client_local_filepath);
    QFileInfo client_general_file(client_general_filepath);

    if (!client_general_file.exists() || !client_local_file.exists()) {
        status |= E_DAT_FILES_MISSING;
    } else {
        if (!QFile::setPermissions(client_general_filepath,
                                   QFileDevice::ReadUser |
                                   QFileDevice::WriteUser |
                                   QFileDevice::ExeUser)) {
            status |= E_WRONG_FILE_PERMISSIONS;
            status |= E_CANNOT_ACCESS_DAT_FILES;
        }

        if (!QFile::setPermissions(client_local_filepath,
                                   QFileDevice::ReadUser |
                                   QFileDevice::WriteUser |
                                   QFileDevice::ExeUser)) {
            status |= E_WRONG_FILE_PERMISSIONS;
            status |= E_CANNOT_ACCESS_DAT_FILES;
        }
    }

    if (!checkInternetConnection(QUrl(Settings::getValue("Network/patch_updates_url").toString()))) {
        status |= E_NO_SERVER_CONNECTION;
    }

    qDebug() << "LegacyApplication: StatusCheck: " << AppErrorStatus(status);
    return AppErrorStatus(status);
}

QDebug operator<<(QDebug dbg, const AppErrorStatus &status)
{
    bool wrong_game_folder = (status & E_WRONG_GAME_FOLDER);
    bool dat_files_missing = (status & E_DAT_FILES_MISSING);
    bool wrong_file_permissions = (status & E_WRONG_FILE_PERMISSIONS);
    bool cannot_access_dat_files = (status & E_CANNOT_ACCESS_DAT_FILES);
    bool dat_file_incorrect = (status & E_DAT_FILE_INCORRECT);
    bool no_server_connection = (status & E_NO_SERVER_CONNECTION);

    dbg.nospace() << "ErrorStatus ( "
        << (wrong_game_folder ? "Wrong game folder! " : "")
        << (dat_files_missing ? "Dat files missing! " : "")
        << (wrong_file_permissions ? "Wrong file permissions! " : "")
        << (cannot_access_dat_files ? "Cannot access dat files! " : "")
        << (dat_file_incorrect ? "Incorrect dat file! " : "")
        << (no_server_connection ? "No server connection! " : "")
        << ")";

    return dbg;
}
