/*
    SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
    SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "KRunnerPlugininstallerRcJob.h"

#include "ScriptConfirmationDialog.h"
#include <KDesktopFile>
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QFileInfo>

static QString installDBusServicePath(const QString &dbusService)
{
    const QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
    QDir dbusDir(dataLocation + "/dbus-1/services/");
    dbusDir.mkpath(("."));
    return dbusDir.filePath(dbusService + ".service");
}

static QString installMetaDataPath(const QString &filePath)
{
    const QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
    QDir krunnerPluginsDir(dataLocation + "/krunner/dbusplugins/");
    krunnerPluginsDir.mkpath(("."));
    // Get the filename in case the .krunner-plugininstallerrc has specified the file to be in a subdir
    return krunnerPluginsDir.filePath(QFileInfo(filePath).fileName());
}

static InstallerInfo getInstallerInfo(const QFileInfo &info)
{
    const QDir rootDir = info.absoluteDir();
    QString installerConfigFile = info.absoluteFilePath();
    Q_ASSERT(installerConfigFile.endsWith("krunner-plugininstallerrc"));

    KConfig cfg(installerConfigFile);
    KConfigGroup grp = cfg.group(QStringLiteral(""));
    const QString exec = grp.readEntry("Exec").replace(QStringLiteral("%{PROJECTDIR}"), info.absolutePath());
    const QString metaDataFile = grp.readEntry("MetaDataFile");
    KDesktopFile desktopFile(rootDir.absoluteFilePath(metaDataFile));
    QString dbusService = desktopFile.desktopGroup().readEntry("X-Plasma-DBusRunner-Service");

    return {exec, dbusService, rootDir.absoluteFilePath(metaDataFile)};
}

void KRunnerPluginInstallerRcJob::executeOperation(const QFileInfo &fileInfo, const QString & /*mimeType*/, bool install)
{
    const InstallerInfo info = getInstallerInfo(fileInfo);
    if (info.exec.isEmpty() || info.desktopFilePath.isEmpty()) {
        Q_EMIT error("The provided installer file is invalid. Please contact the author.");
        return;
    }
    if (install) {
        if (m_skipConfirmDialog || ScriptConfirmationDialog(QString(), install, fileInfo.absolutePath(), info).exec() == QDialog::Accepted) {
            doInstall(info);
        } else {
            Q_EMIT error(QString());
        }
    } else {
        doUninstall(info);
    }
}

void KRunnerPluginInstallerRcJob::doInstall(const InstallerInfo &info)
{
    QFile serviceFile(installDBusServicePath(info.dbusService));

    if (serviceFile.open(QIODevice::WriteOnly)) {
        serviceFile.write(
            QLatin1String("# autogenerated by krunner-plugininstaller\n[D-BUS Service]\nName=%1\nExec=%2\n").arg(info.dbusService, info.exec).toLocal8Bit());
        serviceFile.close();
        qInfo() << "Wrote autostart file" << serviceFile.fileName();
    } else {
        Q_EMIT error(serviceFile.errorString());
        return;
    }

    const QString targetFilePath = installMetaDataPath(info.desktopFilePath);
    // In case we update an entry, simply remove a previous file
    if (QFileInfo::exists(targetFilePath)) {
        qInfo() << "Trying to remove old desktop file" << targetFilePath;
        QFile::remove(targetFilePath);
    }

    if (!QFile::copy(info.desktopFilePath, targetFilePath)) {
        qWarning() << "Failed to copy " << info.desktopFilePath << targetFilePath;
        Q_EMIT error(i18n("Failed to copy file %1 to %2", info.desktopFilePath, targetFilePath));
    } else {
        qInfo() << "Copied desktop file to" << targetFilePath;
        Q_EMIT finished();
    }
}
void KRunnerPluginInstallerRcJob::doUninstall(const InstallerInfo &info)
{
    QFile dbusFile(installDBusServicePath(info.dbusService));
    QFile metaDataFile(installMetaDataPath(info.desktopFilePath));

    if (metaDataFile.remove()) {
        if (dbusFile.remove()) {
            Q_EMIT finished();
        } else {
            Q_EMIT error(xi18nc("@info", "Failed to remove file %1:<nl/>%2", dbusFile.fileName(), dbusFile.errorString()));
        }
    } else {
        Q_EMIT error(xi18nc("@info", "Failed to remove file %1:<nl/>%2", metaDataFile.fileName(), metaDataFile.errorString()));
    }
}
