#include "launcher.h"

#include <QDebug>
#include <QObject>
#include <QWidget>
#include <QDir>
#include <QCoreApplication>
#include <QString>
#include <QList>
#include <QJsonDocument>
#include <QEventLoop>

#include "profile_handler/forge1_12_2.h"
#include "../ui/mainwindow.h"
#include "../../resources/ui_mainwindow.h"


Launcher::Launcher(QObject *parent) : 
    QObject(parent),
    process(new QProcess(this)), 
    get_args(new forge1_12_2()), 
    run_status(false),
    mainWindow(qobject_cast<MainWindow *>(parent)),
    app_dir(QDir(QCoreApplication::applicationDirPath()))
{
	OS_type = "linux";
	#ifdef Q_OS_WIN
        QString vcsBinPath = app_dir.absoluteFilePath(".vcs/bin");
        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
        QString currentPath = env.value("PATH");
        QString newPath = QString("%1;%2").arg(vcsBinPath, currentPath);
        _putenv_s("PATH", newPath.toUtf8().constData());
        OS_type = "win";
	#endif
}


Launcher::~Launcher() {
    delete process;
    delete get_args;
}


void Launcher::startProcess(QString &username, QString &uuid, QString &access_token) {
    if (run_status) { return; } run_status = true;

    selected_profile = this->mainWindow->ui->selected_profile->currentText();
    client_dir = app_dir.absolutePath() + "/" + selected_profile;
    json_settings = this->mainWindow->settings->loadFromJson(selected_profile);
    java_path = json_settings["java_path"].toString();
    RAM = json_settings["RAM"].toString();
    garbarge_collector = json_settings["garbarge_collector"].toString();

    if (selected_profile == "ZombieExtrieme") {
        RAM = RAM.isEmpty() ? this->mainWindow->ui->settings_ram->placeholderText() : RAM;
        java_path = java_path.isEmpty() ? app_dir.absolutePath() + QDir::toNativeSeparators("/java/zulu8/bin/java") : java_path;
        garbarge_collector = garbarge_collector.isEmpty() ? "default_collector" : garbarge_collector;
        version = "1.12.2";
    }
	arguments = get_args->getCrossPlatformArgs(RAM, username, uuid, access_token, garbarge_collector);

    QEventLoop loop;
    connect(this, &Launcher::updateFinished, &loop, &QEventLoop::quit);
    update();
    loop.exec();

    process->setWorkingDirectory(client_dir);
    process->start(java_path, arguments);
	this->mainWindow->hide();
    if (!process->waitForStarted()) {
        qDebug() << process->errorString();
        run_status = false;
        return;
    }

    connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this](int, QProcess::ExitStatus) { 
		this->mainWindow->show();
		run_status = false;
    });
}


void Launcher::update() {
    QProcess *rsyncProcess = new QProcess(this);
    rsyncProcess->setWorkingDirectory(app_dir.absolutePath());

    connect(rsyncProcess, &QProcess::readyReadStandardOutput, [this, rsyncProcess]() {
        QString output = rsyncProcess->readAllStandardOutput();
        QStringList lines = output.split('\n');
        if (!lines.isEmpty()) {
            QString lastLine = lines.last().trimmed();
            int pos = lastLine.indexOf('(');
            if (pos != -1) {
                lastLine = lastLine.left(pos).trimmed();
            }
            if (!lastLine.isEmpty()) {
                this->mainWindow->ui->download_bar->setText(lastLine);
            }
        }
    });
    connect(rsyncProcess, &QProcess::readyReadStandardError, [this, rsyncProcess]() {
        QString errorOutput = rsyncProcess->readAllStandardError();
        this->mainWindow->ui->download_bar->setText(errorOutput);
        qDebug() << errorOutput;
    });

    QStringList rsyncArgs;
    rsyncArgs << "-azH" << "--info=progress2" << "--no-perms" << "--no-owner" << "--no-group";
    if (version == "1.12.2") {
        sync_dirs 
			<< "java/zulu8"
			<< "versions/1.12.2"
			<< "libraries/1.12.2"
			<< selected_profile;
		sync_files 
			<< "PunkLauncher"
			<< "PunkLauncher.exe";
    }
    for (const QString &dir : sync_dirs) { rsyncArgs << "--include=" + dir + "/**"; }
    for (const QString &file : sync_files) { rsyncArgs << "--include=" + file; }
    QStringList exclude_exist_files = {
        "./" + selected_profile + "/options.txt",
        "./" + selected_profile + "/optionsof.txt",
        "./" + selected_profile + "/optionsshaders.txt"
	};
    for (const QString &filePath : exclude_exist_files) {
        QFileInfo fileInfo(filePath);
        if (fileInfo.exists() && fileInfo.isFile()) {
            QString relativePath = QDir().relativeFilePath(fileInfo.absoluteFilePath());
            rsyncArgs << "--exclude=" + relativePath;
        }
    }
    rsyncArgs << "--exclude=./*";
    rsyncArgs << "punkcraft.ru::PunkCraft/" + OS_type + "/uncompressed/" << "./";

    rsyncProcess->start("rsync", rsyncArgs);
    if (!rsyncProcess->waitForStarted()) {
        qDebug() << "Failed to start rsync process";
        qDebug() << rsyncProcess->errorString();
        emit updateFinished();  
        return;
    }

    connect(rsyncProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this, rsyncProcess]() {
		QProcess *rsyncProcess2 = new QProcess(this);
        rsyncProcess->deleteLater();
        rsyncProcess2->setWorkingDirectory(app_dir.absolutePath());

        QStringList rsyncArgs2;
        rsyncArgs2
			<< "-azH" << "--info=progress2"  << "--no-perms" << "--no-owner" << "--no-group" << "--delete-after"
			<< "--include=" + selected_profile
			<< "--include=" + selected_profile + "/mods/"
			<< "--include=" + selected_profile + "/mods/**"
			<< "--include=" + selected_profile + "/resourcepacks/"
			<< "--include=" + selected_profile + "/resourcepacks/**"
			<< "--exclude=*"
			<< "--exclude=" + selected_profile + "/*"
			<< "punkcraft.ru::PunkCraft/" + OS_type + "/uncompressed/" << "./";

        rsyncProcess2->start("rsync", rsyncArgs2);

        connect(rsyncProcess2, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [this, rsyncProcess2]() {
            rsyncProcess2->deleteLater();
            emit updateFinished();
            this->mainWindow->ui->download_bar->setText("");
			qDebug() << "Rsync process finished";
        });
    });
}
