// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2025 Hannah von Reth <h.vonreth@opencloud.eu>

#include "gui/updatenotifier.h"

#include "gui/application.h"
#include "gui/notifications/systemnotificationmanager.h"

#include "resources/fonticon.h"

#include "libsync/account.h"
#include "libsync/common/version.h"
#include "libsync/networkjobs/jsonjob.h"
#include "libsync/theme.h"

#include <QDesktopServices>

using namespace Qt::Literals::StringLiterals;
using namespace OCC;

Q_LOGGING_CATEGORY(lcUpdateNotifier, "gui.updatenotifier", QtInfoMsg)

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

void UpdateNotifier::checkForUpdates(const AccountPtr &account)
{
    if (Version::withUpdateNotification()) {
        if (!_checkedForUpdate) {
            _checkedForUpdate = true;
            auto *job = new JsonJob(account, account->url(), u"config.json"_s, "GET"_ba, this);
            connect(job, &JsonJob::finishedSignal, this, [job, this] {
                if (job->httpStatusCode() == 200) {
                    const auto server = job->data().value("server"_L1).toString().toUtf8();
                    const auto updateUrl = Theme::instance()->updateCheckUrl();
                    if (updateUrl.isEmpty()) {
                        qCInfo(lcUpdateNotifier) << u"Update notification URL is not configured";
                        return;
                    }
                    auto *updateJob = new JsonJob(job->account(), updateUrl, {}, "GET"_ba,
                        SimpleNetworkJob::UrlQuery{{u"version"_s, Version::versionWithBuildNumber().toString()}, {u"edition"_s, channel()},
                            {u"server"_s, QString::fromUtf8(QCryptographicHash::hash(server, QCryptographicHash::Sha256).toHex())}},
                        {}, this);
                    connect(updateJob, &JsonJob::finishedSignal, this, [updateJob, this] {
                        if (updateJob->httpStatusCode() == 200) {
                            const auto data = updateJob->data().value("channels"_L1).toObject().value(channel()).toObject();
                            if (!data.isEmpty()) {
                                const auto currentVersion = data.value("current_version"_L1).toString();
                                const auto url = QUrl(data.value("url"_L1).toString());
                                if (version() < QVersionNumber::fromString(currentVersion)) {
                                    auto notification = SystemNotificationRequest{tr("Update available"),
                                        tr("A new version %1 is available. You are using version %2.",
                                            "The first placeholder is the new version, the second one the current version")
                                            .arg(currentVersion, version().toString()),
                                        Resources::FontIcon(u'')};

                                    const QString buttonText = tr("Open Download Page");
                                    notification.setButtons({buttonText});
                                    auto *sysNotification = ocApp()->systemNotificationManager()->notify(std::move(notification));
                                    connect(sysNotification, &SystemNotification::buttonClicked, this, [buttonText, url](const QString &button) {
                                        if (button == buttonText) {
                                            QDesktopServices::openUrl(url);
                                        }
                                    });
                                }
                            }
                        } else {
                            qCWarning(lcUpdateNotifier) << u"Update check failed with HTTP code" << updateJob->httpStatusCode();
                        }
                    });
                    updateJob->start();
                } else {
                    qCWarning(lcUpdateNotifier) << u"Update check config.json with HTTP code" << job->httpStatusCode();
                }
            });

            job->start();
        }
    }
}

QString UpdateNotifier::channel() const
{
    return Version::isBeta() ? u"beta"_s : u"stable"_s;
}

QVersionNumber UpdateNotifier::version() const
{
    return Version::isBeta() ? Version::versionWithBuildNumber() : Version::version();
}
