#include "launcherbackend.h"

#include <QDesktopServices>
#include <QDir>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStandardPaths>
#include <QUrl>
#include <algorithm>

LauncherBackend::LauncherBackend(QObject *parent)
    : QObject(parent)
    , m_dataDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))
{
    QDir().mkpath(m_dataDir);
    loadData();
}

QStringList LauncherBackend::profileNames() const
{
    QStringList names;
    for (const auto &p : m_profiles)
        names << p.name;
    return names;
}

QStringList LauncherBackend::versionNames() const
{
    QStringList names;
    for (const auto &v : m_versions)
        names << v.name;
    return names;
}

void LauncherBackend::addProfile(const QString &name, const QString &login, const QString &password)
{
    m_profiles.append({m_nextProfileId++, name, login, password});
    saveProfiles();
    emit profilesChanged();
}

void LauncherBackend::addVersion(const QString &name, const QString &serverUrl)
{
    m_versions.append({m_nextVersionId++, name, serverUrl});
    saveVersions();
    emit versionsChanged();
}

void LauncherBackend::updateProfile(int index, const QString &name, const QString &login, const QString &password)
{
    if (index < 0 || index >= m_profiles.size())
        return;
    m_profiles[index].name = name;
    m_profiles[index].login = login;
    m_profiles[index].password = password;
    saveProfiles();
    emit profilesChanged();
}

void LauncherBackend::updateVersion(int index, const QString &name, const QString &serverUrl)
{
    if (index < 0 || index >= m_versions.size())
        return;
    m_versions[index].name = name;
    m_versions[index].serverUrl = serverUrl;
    saveVersions();
    emit versionsChanged();
}

QVariantMap LauncherBackend::profileAt(int index) const
{
    if (index < 0 || index >= m_profiles.size())
        return {};
    const auto &p = m_profiles[index];
    return {{"name", p.name}, {"login", p.login}, {"password", p.password}};
}

QVariantMap LauncherBackend::versionAt(int index) const
{
    if (index < 0 || index >= m_versions.size())
        return {};
    const auto &v = m_versions[index];
    return {{"name", v.name}, {"serverUrl", v.serverUrl}};
}

void LauncherBackend::removeProfile(int index)
{
    if (index < 0 || index >= m_profiles.size())
        return;
    m_profiles.removeAt(index);
    saveProfiles();
    emit profilesChanged();
}

void LauncherBackend::removeVersion(int index)
{
    if (index < 0 || index >= m_versions.size())
        return;
    m_versions.removeAt(index);
    saveVersions();
    emit versionsChanged();
}

void LauncherBackend::launchGame(int profileIndex, int versionIndex)
{
    if (profileIndex < 0 || profileIndex >= m_profiles.size()) {
        emit launchError("Выберите профиль перед запуском");
        return;
    }
    if (versionIndex < 0 || versionIndex >= m_versions.size()) {
        emit launchError("Выберите версию перед запуском");
        return;
    }

    const auto &profile = m_profiles[profileIndex];
    const auto &version = m_versions[versionIndex];
    emit launched(profile.name, version.name, version.serverUrl);
}

QString LauncherBackend::minecraftDir() const
{
#if defined(Q_OS_WIN)
    return QDir::homePath() + "/AppData/Roaming/.minecraft";
#elif defined(Q_OS_MACOS)
    return QDir::homePath() + "/Library/Application Support/minecraft";
#else // Linux и прочие Unix-системы
    return QDir::homePath() + "/.minecraft";
#endif
}

void LauncherBackend::openMinecraftFolder()
{
    const QString modsDir = minecraftDir() + "/mods";
    QDir().mkpath(modsDir);

    if (!QDesktopServices::openUrl(QUrl::fromLocalFile(modsDir)))
        emit launchError("Не удалось открыть папку с модами");
}

void LauncherBackend::loadData()
{
    auto loadFile = [](const QString &path, auto handler) {
        QFile f(path);
        if (!f.open(QIODevice::ReadOnly))
            return;
        for (const auto &val : QJsonDocument::fromJson(f.readAll()).array())
            handler(val.toObject());
    };

    loadFile(m_dataDir + "/profiles.json", [this](const QJsonObject &o) {
        int id = o["id"].toInt();
        m_profiles.append({id, o["name"].toString(), o["login"].toString(), o["password"].toString()});
        if (id >= m_nextProfileId)
            m_nextProfileId = id + 1;
    });
    std::sort(m_profiles.begin(), m_profiles.end(),
              [](const Profile &a, const Profile &b) { return a.id < b.id; });

    loadFile(m_dataDir + "/versions.json", [this](const QJsonObject &o) {
        int id = o["id"].toInt();
        m_versions.append({id, o["name"].toString(), o["serverUrl"].toString()});
        if (id >= m_nextVersionId)
            m_nextVersionId = id + 1;
    });
    std::sort(m_versions.begin(), m_versions.end(),
              [](const Version &a, const Version &b) { return a.id < b.id; });
}

void LauncherBackend::saveProfiles()
{
    QJsonArray arr;
    for (const auto &p : m_profiles)
        arr.append(QJsonObject{{"id", p.id}, {"name", p.name}, {"login", p.login}, {"password", p.password}});

    QFile f(m_dataDir + "/profiles.json");
    if (f.open(QIODevice::WriteOnly))
        f.write(QJsonDocument(arr).toJson());
}

void LauncherBackend::saveVersions()
{
    QJsonArray arr;
    for (const auto &v : m_versions)
        arr.append(QJsonObject{{"id", v.id}, {"name", v.name}, {"serverUrl", v.serverUrl}});

    QFile f(m_dataDir + "/versions.json");
    if (f.open(QIODevice::WriteOnly))
        f.write(QJsonDocument(arr).toJson());
}
