/*
 *   SPDX-FileCopyrightText: 2020 Alexey Minnekhanov <alexey.min@gmail.com>
 *
 *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
 */

#include "AlpineApkTransaction.h"
#include "AlpineApkAuthActionFactory.h"
#include "AlpineApkBackend.h"
#include "AlpineApkResource.h"
#include "alpineapk_backend_logging.h" // generated by ECM

// Qt
#include <QDebug>
#include <QTimer>

// KF5
#include <KAuth/ExecuteJob>
#include <KLocalizedString>
#include <kcoreaddons_version.h>

AlpineApkTransaction::AlpineApkTransaction(AlpineApkResource *res, Role role)
    : AlpineApkTransaction(res, {}, role)
{
}

AlpineApkTransaction::AlpineApkTransaction(AlpineApkResource *res, const AddonList &addons, Transaction::Role role)
    : Transaction(res->backend(), res, role, addons)
    , m_resource(res)
    , m_backend(static_cast<AlpineApkBackend *>(res->backend()))
{
    setCancellable(false);
    setStatus(QueuedStatus);
    // seems like Discover's transactions are supposed to start
    // automatically; no dedicated method to start transaction?
    startTransaction();
}

void AlpineApkTransaction::proceed()
{
    startTransaction();
}

void AlpineApkTransaction::cancel()
{
    setStatus(CancelledStatus);
}

void AlpineApkTransaction::startTransaction()
{
    KAuth::ExecuteJob *reply = nullptr;
    switch (role()) {
    case InstallRole:
        reply = ActionFactory::createAddAction(m_resource->m_pkg.name);
        break;
    case RemoveRole:
        reply = ActionFactory::createDelAction(m_resource->m_pkg.name);
        break;
    case ChangeAddonsRole:
        qCWarning(LOG_ALPINEAPK) << "Addons are not supported by Alpine APK Backend!";
        break;
    }

    if (!reply) {
        return;
    }

    // get result of this job
    QObject::connect(reply, &KAuth::ExecuteJob::result, this, [this](KJob *job) {
        KAuth::ExecuteJob *reply = static_cast<KAuth::ExecuteJob *>(job);
        const QVariantMap &replyData = reply->data();
        if (reply->error() == 0) {
            finishTransactionOK();
        } else {
            QString message = replyData.value(QLatin1String("errorString"), reply->errorString()).toString();
            if (reply->error() == KAuth::ActionReply::Error::AuthorizationDeniedError) {
                message = i18n("Error: Authorization denied");
            }
            finishTransactionWithError(message);
        }
    });

    // get progress reports for this job
    QObject::connect(reply, &KAuth::ExecuteJob::percentChanged, this, [this](KJob *job, unsigned long percent) {
        Q_UNUSED(job)
        if (percent >= 40 && role() == InstallRole) {
            setStatus(CommittingStatus);
        }
        setProgress(static_cast<int>(percent));
    });

    setProgress(0);
    if (role() == InstallRole) {
        setStatus(DownloadingStatus);
    } else {
        setStatus(CommittingStatus);
    }

    reply->start();
}

void AlpineApkTransaction::finishTransactionOK()
{
    AbstractResource::State newState;
    switch (role()) {
    case InstallRole:
    case ChangeAddonsRole:
        newState = AbstractResource::Installed;
        break;
    case RemoveRole:
        newState = AbstractResource::None;
        break;
    }
    m_resource->setAddons(addons());
    m_resource->setState(newState);
    setStatus(DoneStatus);
    deleteLater();
}

void AlpineApkTransaction::finishTransactionWithError(const QString &errMsg)
{
    qCWarning(LOG_ALPINEAPK) << "Transaction finished with error:" << errMsg;
    Q_EMIT passiveMessage(i18n("Error") + QStringLiteral(":\n") + errMsg);
    setStatus(DoneWithErrorStatus);
    deleteLater();
}
