#pragma once

#include "javaruntime.h"

#include <QDateTime>
#include <QHash>
#include <QList>
#include <QObject>
#include <QSet>

#include <functional>

class QNetworkAccessManager;

// Каталог сборок Java, которые лаунчер умеет скачать: качает, кэширует в папке
// лаунчера и отдаёт из кэша, пока тот не устарел. Устроен как
// VersionManifestService и работает в GUI-потоке.
//
// Источников два и они дополняют друг друга:
//
//  * Mojang (категория «Java») — ровно тот рантайм, которым запускает игру
//    официальный лаунчер. Версий немного, зато они заведомо совместимы.
//
//  * Eclipse Temurin (категории JDK и JRE) — свежие сборки всех мажорных
//    версий, включая те, до которых Mojang ещё не дошёл.
//
// Отдаются только сборки под текущие ОС и архитектуру: выбрать заведомо
// неработающую нечем. Исключение — macOS на Apple Silicon, где под Java 8 и 16
// сборок aarch64 нет вовсе и приходится брать x64 (работает через Rosetta).
class JavaRuntimeService : public QObject
{
    Q_OBJECT

public:
    // ok = true и непустой warning — данные отдали из устаревшего кэша.
    using Callback = std::function<void(bool ok, const QString &warning)>;

    explicit JavaRuntimeService(QObject *parent = nullptr);

    void ensureLoaded(Callback callback, bool forceRefresh = false);

    // Новые версии сверху.
    QList<JavaRuntimeEntry> entries(JavaRuntimeKind kind) const;
    std::optional<JavaRuntimeEntry> find(const QString &id) const;

    bool isRefreshing() const { return m_outstanding > 0; }
    bool hasData() const { return !m_entries.isEmpty(); }

signals:
    void catalogChanged();
    void refreshingChanged();

private:
    void startRefresh();
    void requestAdoptiumReleases();
    // allowFallback — на macOS/aarch64 разрешено переспросить сборку под x64.
    void requestFeatureRelease(int major, const QString &architecture, bool allowFallback);
    void requestMojangRuntimes();

    // Общий хвост любого запроса: считает незавершённые и, когда их не
    // осталось, применяет накопленное.
    void requestFinished(const QString &warning);
    void finishRefresh();

    static QList<JavaRuntimeEntry> parseAdoptium(const QByteArray &payload,
                                                 const QSet<int> &ltsVersions);
    static QList<JavaRuntimeEntry> parseMojang(const QByteArray &payload);

    void applyEntries(QList<JavaRuntimeEntry> list);
    bool readCache();
    void writeCache();

    QNetworkAccessManager *m_network;

    QList<JavaRuntimeEntry> m_entries;
    QHash<QString, int> m_indexById;
    QDateTime m_fetchedAt;
    bool m_cacheRead = false;

    // Накопитель одного обновления: ответы приходят вразнобой, каталог
    // подменяется целиком и только когда пришли все.
    QList<JavaRuntimeEntry> m_incoming;
    QStringList m_warnings;
    QSet<int> m_ltsVersions;
    int m_outstanding = 0;

    QList<Callback> m_pending;
};
