#pragma once

#include "modloader.h"

#include <QObject>
#include <QString>
#include <QStringList>

class QNetworkAccessManager;
class QNetworkReply;
class QProcess;
class ModLoaderVersionService;
class VersionInstaller;

// Установка модлоадера в .minecraft. Два разных пути под одним фасадом:
//
//  * Fabric и Quilt отдают готовое описание версии — кладём его в
//    versions/<id>/<id>.json и передаём дальше VersionInstaller, который по
//    inheritsFrom сам поставит ванильную версию и библиотеки лоадера.
//
//  * Forge и NeoForge так не умеют: их установка — это патч клиентского jar,
//    поэтому запускаем официальный installer.jar найденной Java в headless-режиме
//    и смотрим, какой профиль появился в versions.
//
// Набор геттеров повторяет VersionInstaller: панель загрузки в интерфейсе
// читает их одинаково, независимо от того, кто сейчас работает.
class ModLoaderInstaller : public QObject
{
    Q_OBJECT

public:
    ModLoaderInstaller(ModLoaderVersionService *meta,
                       VersionInstaller *versionInstaller,
                       QObject *parent = nullptr);
    ~ModLoaderInstaller() override;

    bool isRunning() const { return m_running; }
    QString label() const { return m_label; }
    QString stage() const { return m_stage; }
    QString currentFile() const { return m_currentFile; }

    qint64 bytesDone() const { return m_bytesDone; }
    qint64 bytesTotal() const { return m_bytesTotal; }
    double fraction() const;   // 0..1, либо -1 пока итог неизвестен

    void install(const QString &gameDir,
                 ModLoader loader,
                 const QString &gameVersion,
                 const QString &loaderVersion,
                 const QString &javaPreference);
    void cancel();

signals:
    void started(const QString &label);
    void progressChanged();
    void finished(const QString &loaderKey,
                  const QString &gameVersion,
                  const QString &loaderVersion,
                  const QString &producedVersionId);
    void failed(const QString &label, const QString &message);
    void canceled(const QString &label);
    void log(const QString &line);

private:
    void beginFabricLike();
    void beginInstallerJar();
    void ensureBaseVersion(std::function<void()> next);
    void downloadInstaller(const QUrl &url, std::function<void(const QString &)> next);
    bool writeLauncherProfilesStub();
    void runInstaller(const QString &installerPath);
    void handleInstallerFinished(int exitCode, bool crashed);

    void handOffToVersionInstaller(const QString &versionId);
    void setStage(const QString &stage);
    void reset();
    void fail(const QString &message);

    ModLoaderVersionService *m_meta;
    VersionInstaller *m_versionInstaller;
    QNetworkAccessManager *m_network;
    QNetworkReply *m_reply = nullptr;
    QProcess *m_process = nullptr;

    QString m_gameDir;
    ModLoader m_loader = ModLoader::Fabric;
    QString m_gameVersion;
    QString m_loaderVersion;
    QString m_javaPreference;
    QString m_label;

    QString m_stage;
    QString m_currentFile;
    qint64 m_bytesDone = 0;
    qint64 m_bytesTotal = 0;

    // Профили, которые были в versions до запуска installer.jar: новый ищем
    // разницей, а не угадыванием строки — id у Forge разные по эпохам.
    QStringList m_versionsBefore;
    QStringList m_installerLog;

    // Ждём, пока VersionInstaller докачает то, что установщик не положил.
    QString m_awaitingVersionId;

    bool m_running = false;
    bool m_canceling = false;
};
