//========================================================================
//
// check_signature_basics.cpp
//
// This file is licensed under the GPLv2 or later
//
// Copyright 2023-2025 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
// Copyright 2025, 2026 Albert Astals Cid <aacid@kde.org>
//========================================================================

// Simple tests of reading signatures
//
// Note that this does not check the actual validity because
// that will have an expiry date, and adding time bombs to unit tests is
// probably not a good idea.
#include <QtTest/QTest>
#include <QTemporaryDir>
#include "Form.h"
#include "PDFDoc.h"
#include "GlobalParams.h"
#include "SignatureInfo.h"
#include "CryptoSignBackend.h"
#include "config.h"
#if ENABLE_GPGME
#    include <gpgme++/global.h>
#    include "GPGMECryptoSignBackendConfiguration.h"
#    include <gpgme++/importresult.h>
#    include <gpgme++/context.h>
#    include <gpgme++/data.h>
#endif

#if ENABLE_GPGME
const auto pubkey = R"ZxZ(
-----BEGIN PGP PUBLIC KEY BLOCK-----

[encoded data, 4615 characters]
xujPUZsL
=x7r+
-----END PGP PUBLIC KEY BLOCK-----
)ZxZ";
#endif

class TestSignatureBasicsPgpSignature : public QObject
{
    Q_OBJECT
public:
    explicit TestSignatureBasicsPgpSignature(QObject *parent = nullptr) : QObject(parent) { }

    static std::unique_ptr<QTemporaryDir> tmpdir;
    static void initMain()
    {
#if ENABLE_GPGME
        tmpdir = std::make_unique<QTemporaryDir>();
        qputenv("GNUPGHOME", tmpdir->path().toLocal8Bit().data());
        GpgME::initializeLibrary();
        auto ctx = GpgME::Context::create(GpgME::Protocol::OpenPGP);
        QVERIFY(ctx);
        GpgME::Data d;
        d.write(pubkey, strlen(pubkey));
        d.rewind();
        auto result = ctx->importKeys(d);
        QCOMPARE(result.numImported(), 1);
#endif // ENABLE_GPGME
    }
private Q_SLOTS:
    static void init();
    static void initTestCase_data();
    void initTestCase() { }
    static void testPgp();
};

std::unique_ptr<QTemporaryDir> TestSignatureBasicsPgpSignature::tmpdir;

void TestSignatureBasicsPgpSignature::init()
{
#if ENABLE_SIGNATURES
    QFETCH_GLOBAL(CryptoSign::Backend::Type, backend);
    CryptoSign::Factory::setPreferredBackend(backend);
    QCOMPARE(CryptoSign::Factory::getActive(), backend);
#endif
    globalParams = std::make_unique<GlobalParams>();
}

void TestSignatureBasicsPgpSignature::initTestCase_data()
{
    QTest::addColumn<CryptoSign::Backend::Type>("backend");

#if ENABLE_SIGNATURES
    const auto availableBackends = CryptoSign::Factory::getAvailable();

#    if ENABLE_NSS3
    if (std::ranges::find(availableBackends, CryptoSign::Backend::Type::NSS3) != availableBackends.end()) {
        QTest::addRow("nss") << CryptoSign::Backend::Type::NSS3;
    } else {
        QWARN("Compiled with NSS3, but NSS not functional");
    }
#    endif
#    if ENABLE_GPGME
    if (std::ranges::find(availableBackends, CryptoSign::Backend::Type::GPGME) != availableBackends.end()) {
        QTest::addRow("gpg") << CryptoSign::Backend::Type::GPGME;
    } else {
        QWARN("Compiled with GPGME, but GPGME not functional");
    }
#    endif
#endif
}

void TestSignatureBasicsPgpSignature::testPgp()
{
    std::optional<CryptoSign::Backend::Type> usedBackend;
#if ENABLE_GPGME
    QFETCH_GLOBAL(CryptoSign::Backend::Type, backend);
    usedBackend = backend;
    if (backend == CryptoSign::Backend::Type::GPGME) {
        GpgSignatureConfiguration::setPgpSignaturesAllowed(true);
    }
#endif
    auto gpgDoc = std::make_unique<PDFDoc>(std::make_unique<GooString>(TESTDATADIR "/unittestcases/some-text-pgp_signed.pdf"));
    auto signatureFields = gpgDoc->getSignatureFields();
    QCOMPARE(signatureFields.size(), 1);
    QCOMPARE(signatureFields[0]->getSignatureType(), CryptoSign::SignatureType::g10c_pgp_signature_detached);
    QVERIFY(!signatureFields[0]->getSignature().empty());
    auto [sig0, size0] = signatureFields[0]->getCheckedSignature();
    QVERIFY(sig0);
    auto ranges0 = signatureFields[0]->getSignedRangeBounds();
    QCOMPARE(ranges0.size(), 4);
    QCOMPARE(ranges0[0], 0);
    QCOMPARE(ranges0[1], 82991);
    QCOMPARE(ranges0[2], 102993);
    QCOMPARE(ranges0[3], 103534);

    auto *siginfo0 = signatureFields[0]->validateSignatureAsync(false, false, -1 /* now */, false, false, {});
    signatureFields[0]->validateSignatureResult();
    if (usedBackend == CryptoSign::Backend::Type::GPGME) {
        QCOMPARE(siginfo0->getSignerName(), std::string { "Sune Vuorela" });
        QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Sha256);
        QCOMPARE(siginfo0->getCertificateInfo()->getPublicKeyInfo().publicKeyStrength, 4096);
        QCOMPARE(siginfo0->getCertificateInfo()->getNickName().toStr().substr(32), std::string { "F1F0D3ED" });
        QCOMPARE(siginfo0->getSignatureValStatus(), SignatureValidationStatus::SIGNATURE_VALID);
    } else {
        QCOMPARE(siginfo0->getSignerName(), std::string {});
        QCOMPARE(siginfo0->getHashAlgorithm(), HashAlgorithm::Unknown);
        QCOMPARE(siginfo0->getCertificateInfo(), nullptr);
        QCOMPARE(siginfo0->getSignatureValStatus(), SignatureValidationStatus::SIGNATURE_NOT_VERIFIED);
    }
}

QTEST_GUILESS_MAIN(TestSignatureBasicsPgpSignature)
#include "check_signature_basics_pgp.moc"
