// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
// SPDX-License-Identifier: GPL-3.0-or-later

#include "App/Core/UpdateChecker.h"

#include <QDate>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QVersionNumber>

#include "App/Core/Settings.h"
#include "App/Versions.h"

static constexpr auto k_apiUrl = "https://api.github.com/repos/gibis-unifesp/wiredpanda/releases/latest";

UpdateChecker::UpdateChecker(QObject *parent)
    : QObject(parent)
{
}

void UpdateChecker::checkForUpdates()
{
    // Skip if we already checked today.
    const QString today = QDate::currentDate().toString(Qt::ISODate);
    if (Settings::updateCheckLastDate() == today) {
        return;
    }

    QNetworkRequest request{QUrl(k_apiUrl)};
    request.setHeader(QNetworkRequest::UserAgentHeader, "wiRedPanda/" APP_VERSION);
    request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
                         QNetworkRequest::NoLessSafeRedirectPolicy);

    QNetworkReply *reply = m_network.get(request);
    connect(reply, &QNetworkReply::finished, this, [this, reply] { onReplyFinished(reply); });
}

void UpdateChecker::onReplyFinished(QNetworkReply *reply)
{
    reply->deleteLater();

    if (reply->error() != QNetworkReply::NoError) {
        return;
    }

    const QJsonDocument doc = QJsonDocument::fromJson(reply->readAll());
    if (doc.isNull() || !doc.isObject()) {
        return;
    }

    const QString tagName = doc.object().value("tag_name").toString();
    const QVersionNumber latest = QVersionNumber::fromString(tagName).normalized();
    if (latest.isNull() || latest <= AppVersion::current) {
        return;
    }

    // Respect the user's per-version suppression.
    if (latest.toString() == Settings::updateCheckSkippedVersion()) {
        return;
    }

    QUrl downloadUrl;
    const QJsonArray assets = doc.object().value("assets").toArray();
    for (const QJsonValue &assetVal : assets) {
        const QJsonObject asset = assetVal.toObject();
        const QString name = asset.value("name").toString();
#if defined(Q_OS_WIN)
        const bool match = name.contains("Windows") && name.endsWith(".zip");
#elif defined(Q_OS_MACOS)
        const bool match = name.contains("macOS") && name.endsWith(".dmg");
#elif defined(Q_OS_LINUX)
        const bool match = name.endsWith(".AppImage");
#else
        const bool match = false;
#endif
        if (match) {
            downloadUrl = QUrl(asset.value("browser_download_url").toString());
            break;
        }
    }

    const QUrl releaseUrl = QUrl(doc.object().value("html_url").toString());
    emit updateAvailable(latest.toString(), downloadUrl, releaseUrl);
}

