// SPDX-FileCopyrightText: 2024 g10 code GmbH
// SPDX-Contributor: Carl Schwan <carl.schwan@gnupg.com>
// SPDX-License-Identifier: GPL-2.0-or-later

#include "editor/composerviewbase.h"
#include "editor/job/composerjob.h"
#include "editor/part/textpart.h"
#include "editor/recipientseditor.h"
#include "editor/richtextcomposerng.h"
#include "identity/identity.h"
#include "identity/identitydialog.h"
#include "identity/identitymanager.h"
#include "messagedispatcher.h"
#include <QObject>
#include <QSignalSpy>
#include <QTest>
#include <Sonnet/DictionaryComboBox>
#include <TextCustomEditor/RichTextEditorWidget>

using namespace Qt::StringLiterals;

static QByteArray readMailFromFile(const QString &mailFile)
{
    QFile file(QLatin1StringView(DATA_DIR) + QLatin1Char('/') + mailFile);
    file.open(QIODevice::ReadOnly);
    Q_ASSERT(file.isOpen());
    return file.readAll();
}

class DummyMessageDispatcher : public MessageDispatcher
{
    Q_OBJECT
public:
    void dispatch(const KMime::Message::Ptr &message, const QString &from, const QString &mailId) override
    {
        mMessages.emplace_back(message, from, mailId);
        Q_EMIT sentSuccessfully();
    }

    struct Message {
        KMime::Message::Ptr message;
        QString from;
        QString mailId;
    };
    std::vector<Message> mMessages;
};

class ComposerViewBaseTest : public QObject
{
    Q_OBJECT

private Q_SLOTS:
    void init()
    {
        mComposerBase = std::make_unique<MessageComposer::ComposerViewBase>();
        mComposerBase->setRecipientsEditor(&mRecipientsEditor);
        auto richTextComposer = new MessageComposer::RichTextComposerNg(nullptr);
        mComposerBase->setEditor(richTextComposer);
        mComposerBase->setMessageDispatcher(&mMessageDispatcher);
        mMessageDispatcher.mMessages.clear();
        mComposerBase->setDictionary(&mDictionaryComboBox);
    }

    void testSetMessage()
    {
        KMime::Message::Ptr message(new KMime::Message);
        message->setContent(KMime::CRLFtoLF(readMailFromFile(u"draft.mbox"_s)));
        message->parse();

        mComposerBase->setMessage(message);
        mComposerBase->setFrom(u"carl.from@carlschwan.eu"_s);

        QCOMPARE(mComposerBase->to(), QLatin1StringView("carl.to@carlschwan.eu"));
        QCOMPARE(mComposerBase->cc(), QLatin1StringView("carl.cc@carlschwan.eu"));
        QCOMPARE(mComposerBase->bcc(), QLatin1StringView("carl.bcc@carlschwan.eu"));
        QCOMPARE(mComposerBase->from(), QLatin1StringView("carl.from@carlschwan.eu"));
        QCOMPARE(mComposerBase->subject(), QLatin1StringView("Draft"));

        auto textPart = new MessageComposer::TextPart();
        mComposerBase->editor()->fillComposerTextPart(textPart);
        QCOMPARE(textPart->cleanPlainText(), QLatin1StringView("Draft content"));
    }

    void testSetMessageTooManyRecipient()
    {
        KMime::Message::Ptr message(new KMime::Message);
        message->setContent(KMime::CRLFtoLF(readMailFromFile(u"plaintexttoomanyrecipient.mbox"_s)));
        message->parse();

        QSignalSpy tooManySignal(mComposerBase.get(), &MessageComposer::ComposerViewBase::tooManyRecipient);
        mComposerBase->setMessage(message);
        QCOMPARE(tooManySignal.count(), 1);
    }

    void testSetMessageHtml()
    {
        KMime::Message::Ptr message(new KMime::Message);
        message->setContent(KMime::CRLFtoLF(readMailFromFile(u"html.mbox"_s)));
        message->parse();

        QSignalSpy enableHtmlSignal(mComposerBase.get(), &MessageComposer::ComposerViewBase::enableHtml);
        mComposerBase->setMessage(message);
        QCOMPARE(enableHtmlSignal.count(), 1);

        auto textPart = new MessageComposer::TextPart();
        mComposerBase->editor()->fillComposerTextPart(textPart);
        QCOMPARE(textPart->cleanPlainText(), QLatin1StringView("*SOME* HTML text. \n"));
        QVERIFY(textPart->isHtmlUsed());
        QCOMPARE(textPart->cleanHtml(),
                 QLatin1StringView(
                     "<html>\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n</head>\n<body><p "
                     "style=\"margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;\"><strong>SOME</strong>&nbsp;HTML text. </p>\n</body>\n</html>"));
    }

    void testSendMessageNotEncryptedPlainText()
    {
        mComposerBase->setFrom(u"from@example.com"_s);
        mComposerBase->setSubject(u"Subject"_s);
        mComposerBase->setCryptoOptions(false, false, {});
        mComposerBase->editor()->setText(u"Content"_s);
        mComposerBase->send();

        QCOMPARE(mMessageDispatcher.mMessages.size(), 1);
        QCOMPARE(mMessageDispatcher.mMessages[0].from, u"from@example.com"_s);
        const auto message = mMessageDispatcher.mMessages[0].message;

        QCOMPARE(message->header<KMime::Headers::Subject>()->asUnicodeString(), u"Subject"_s);
        QCOMPARE(message->header<KMime::Headers::From>()->asUnicodeString(), u"from@example.com"_s);
        QCOMPARE(message->header<KMime::Headers::MIMEVersion>()->asUnicodeString(), u"1.0"_s);
        QCOMPARE(message->header<KMime::Headers::ContentTransferEncoding>()->encoding(), KMime::Headers::CE7Bit);
        QVERIFY(message->header<KMime::Headers::ContentType>()->isPlainText());

        QCOMPARE(message->decodedContent(), "Content");
    }

    void testSendMessageNotEncryptedRichText()
    {
        mComposerBase->setFrom(u"from@example.com"_s);
        mComposerBase->setSubject(u"Subject"_s);
        mComposerBase->setCryptoOptions(false, false, {});
        mComposerBase->editor()->activateRichText();
        mComposerBase->editor()->setText(u"<p style=\"color:red\">Content</p>"_s);
        mComposerBase->send();

        QCOMPARE(mMessageDispatcher.mMessages.size(), 1);
        QCOMPARE(mMessageDispatcher.mMessages[0].from, u"from@example.com"_s);
        const auto message = mMessageDispatcher.mMessages[0].message;

        QCOMPARE(message->header<KMime::Headers::Subject>()->asUnicodeString(), u"Subject"_s);
        QCOMPARE(message->header<KMime::Headers::From>()->asUnicodeString(), u"from@example.com"_s);
        QCOMPARE(message->header<KMime::Headers::MIMEVersion>()->asUnicodeString(), u"1.0"_s);
        QCOMPARE(message->header<KMime::Headers::ContentTransferEncoding>()->encoding(), KMime::Headers::CE7Bit);

        QVERIFY(!message->header<KMime::Headers::ContentType>()->isPlainText());

        const auto textPart = message->contents()[0];
        QCOMPARE(textPart->decodedContent(), "Content\n");

        const auto htmlPart = message->contents()[1];
        QCOMPARE(htmlPart->decodedContent(), R"(<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body><p style="margin-top:12;margin-bottom:12;margin-left:0;margin-right:0;"><span style="color:#ff0000;">Content</span></p>
</body>
</html>)");
    }

    void testSendSignedPlainText()
    {
        bool isNew = false;
        auto identity = IdentityManager::self().fromEmail(u"you@you.com"_s, isNew);
        identity.setPGPSigningKey("00949E2AF4A985AFB572FDD214B79E26050467AA");
        mComposerBase->setIdentity(identity);

        mComposerBase->setFrom(u"you@you.com"_s);
        mComposerBase->setSubject(u"Subject"_s);
        mComposerBase->setCryptoOptions(true, false, {});
        mComposerBase->editor()->setText(u"Content"_s);

        mComposerBase->send();

        auto composer = mComposerBase->m_composers[0];
        QSignalSpy spy(composer, &MessageComposer::ComposerJob::result);
        spy.wait();

        QCOMPARE(mMessageDispatcher.mMessages.size(), 1);
        QCOMPARE(mMessageDispatcher.mMessages[0].from, u"you@you.com"_s);
        const auto message = mMessageDispatcher.mMessages[0].message;

        qWarning().noquote() << message->encodedContent();

        QCOMPARE(message->header<KMime::Headers::Subject>()->asUnicodeString(), u"Subject"_s);
        QCOMPARE(message->header<KMime::Headers::From>()->asUnicodeString(), u"you@you.com"_s);
        QCOMPARE(message->header<KMime::Headers::MIMEVersion>()->asUnicodeString(), u"1.0"_s);
        QCOMPARE(message->header<KMime::Headers::ContentType>()->mimeType(), "multipart/signed");

        const auto textPart = message->contents()[0];
        QCOMPARE(textPart->header<KMime::Headers::ContentType>()->mimeType(), "text/plain");
        QCOMPARE(textPart->decodedContent(), "Content");

        const auto signPart = message->contents()[1];
        QCOMPARE(signPart->header<KMime::Headers::ContentType>()->mimeType(), "application/pgp-signature");
        QCOMPARE(signPart->header<KMime::Headers::ContentTransferEncoding>()->encoding(), KMime::Headers::CE7Bit);
    }

private:
    std::unique_ptr<MessageComposer::ComposerViewBase> mComposerBase;
    DummyMessageDispatcher mMessageDispatcher;
    RecipientsEditor mRecipientsEditor;
    Sonnet::DictionaryComboBox mDictionaryComboBox;
};

QTEST_MAIN(ComposerViewBaseTest)
#include "composerviewbasetest.moc"