// SPDX-FileCopyrightText: 2024 g10 Code GmbH
// SPDX-FileContributor: Carl Schwan <carl@carlschwan.eu>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "directoryreencryptjob.h"
#include "filereencryptjob.h"
#include "models/storemodel.h"

#include <KLocalizedString>
#include <QDirIterator>
#include <QDebug>

DirectoryReencryptJob::DirectoryReencryptJob(const StoreModel &storeModel, const QList<QByteArray> &userKeys, const QString &directory, QObject *parent)
    : KCompositeJob(parent)
    , m_directory(directory)
    , m_storeModel(storeModel)
    , m_userKeys(userKeys)
{
}

bool DirectoryReencryptJob::writeGpgIdList()
{
    QString gpgIdFile = m_directory + QStringLiteral(".gpg-id");
    QFile gpgId(gpgIdFile);
    if (!gpgId.open(QIODevice::WriteOnly | QIODevice::Text)) {
        setError(FilePermissionError);
        setErrorText(gpgId.errorString());
        emitResult();
        return false;
    }
    gpgId.write(m_userKeys.join(u'\n'));
    gpgId.close();
    return true;
}

void DirectoryReencryptJob::start()
{
    if (!writeGpgIdList()) {
        return;
    }

    QDirIterator encryptedFilesIterator(m_directory, {QStringLiteral("*.gpg")}, QDir::Files, QDirIterator::Subdirectories);

    QList<QByteArray> recipients;
    QList<QByteArray> rootRecipients = m_storeModel.recipientsForFile(QFileInfo(m_directory));
    QFileInfo currentDirectory;
    if (!encryptedFilesIterator.hasNext()) {
        emitResult();
    }
    while (encryptedFilesIterator.hasNext()) {
        const QString fileName = encryptedFilesIterator.next();
        if (encryptedFilesIterator.fileInfo().path() != currentDirectory.path()) {
            recipients = m_storeModel.recipientsForFile(encryptedFilesIterator.fileInfo());
        }

        if (rootRecipients != recipients) {
            // No need to reencrypt directory which were encrypted for another list of users.
            continue;
        }

        qInfo() << "Started reeencryption of" << fileName << "for recipients" << recipients;

        auto fileReencryptJob = new FileReencryptJob(fileName, recipients);
        const auto isFirstJob = !hasSubjobs();
        addSubjob(fileReencryptJob);
        if (isFirstJob) {
            fileReencryptJob->start();
        }
    }
}

void DirectoryReencryptJob::slotResult(KJob *job)
{
    KCompositeJob::slotResult(job);

    if (job->error() != KJob::NoError) {
        setError(job->error());
        setErrorText(job->errorText());
        qWarning() << job->errorText();
    }

    if (hasSubjobs()) {
        const auto jobs = subjobs();
        jobs.first()->start();
    } else {
        emitResult();
    }
}
