#pragma once

#include "authservice.h"

#include <QJsonObject>
#include <QObject>
#include <QString>
#include <QUrl>
#include <functional>

class QNetworkAccessManager;

// Авторизация через аккаунт Microsoft — та же цепочка, что и в официальном
// лаунчере: OAuth2 -> Xbox Live -> XSTS -> Minecraft Services -> проверка
// лицензии. Результат отдаётся тем же AuthResult, что и Ely.by с офлайном,
// поэтому запуск игры дальше идёт по общему пути.
class MsaAuthService : public QObject
{
    Q_OBJECT

public:
    using Callback = std::function<void(const AuthResult &)>;

    explicit MsaAuthService(QObject *parent = nullptr);

    // Id приложения лаунчера. Игра ждёт его в ${clientid}: официальный лаунчер
    // подставляет туда именно id приложения, а не случайный токен сессии.
    static QString clientId();

    // Адрес страницы входа для встроенного окна.
    static QUrl authorizationUrl();

    // Отличает адрес, на который Microsoft возвращает управление после входа,
    // от остальной навигации внутри окна. Заполняет code либо error.
    static bool matchRedirect(const QUrl &url, QString *code, QString *error);

    // Полный вход по коду из окна браузера.
    void loginWithCode(const QString &code, Callback callback);

    // Продление сессии без участия пользователя. Refresh-токен Microsoft живёт
    // куда дольше суточного токена Minecraft, так что обычно хватает его.
    void loginWithRefreshToken(const QString &refreshToken, Callback callback);

signals:
    void progress(const QString &message);

private:
    using JsonHandler = std::function<void(int status, const QJsonObject &response,
                                           const QString &transportError)>;

    void postForm(const QUrl &url, const QByteArray &body, JsonHandler handler);
    void postJson(const QUrl &url, const QJsonObject &body, const QString &bearer,
                  JsonHandler handler);
    void getJson(const QUrl &url, const QString &bearer, JsonHandler handler);

    // Шаги цепочки. Каждый следующий вызывается из колбэка предыдущего.
    void exchangeToken(const QByteArray &form, Callback callback);
    void authenticateXbox(const QString &microsoftToken, const QString &refreshToken,
                          Callback callback);
    void authorizeXsts(const QString &xblToken, const QString &refreshToken, Callback callback);
    void loginWithXbox(const QString &userHash, const QString &xstsToken, const QString &xuid,
                       const QString &refreshToken, Callback callback);
    void checkLicense(AuthResult result, Callback callback);
    void fetchProfile(AuthResult result, bool storeEntitlement, Callback callback);

    QNetworkAccessManager *m_network;
};
