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

#pragma once

// Qt includes
#include <QUrl>

// KDE includes
#include "identity/identity.h"
#include <KMime/Headers>
#include <KMime/Message>
#include <KXmlGuiWindow>
#include <Libkleo/Enum>
#include <Libkleo/KeyCache>

// App includes
#include "composerwindowfactory.h"

class QSplitter;
class QLabel;
class QPrinter;
class QGridLayout;
class QLineEdit;
class QPushButton;
class KLineEdit;
class RecipientsEditor;
class KToggleAction;
class RecipientLineNG;
class NearExpiryWarning;
class IdentityCombo;
class KMComposerGlobalAction;
class KRecentFilesAction;
class EWSMessageDispatcher;

namespace KPIMTextEdit
{
class RichTextComposerWidget;
class RichTextComposer;
}

namespace TextCustomEditor
{
class RichTextEditorWidget;
}

namespace MessageComposer
{
class ComposerViewBase;
class RichTextComposerNg;
}

namespace Kleo
{
class KeyResolverCore;
class ExpiryChecker;
}

class ComposerWindow : public KXmlGuiWindow
{
    Q_OBJECT

    enum Confirmation {
        LetUserConfirm,
        NoConfirmationNeeded,
    };

public:
    struct AttachmentInfo {
        QString comment;
        QUrl url;
    };

    /// The identity assigned to this message.
    KIdentityManagementCore::Identity identity() const;

    /// The subject of the message.
    QString subject() const;

    /// The recipients of the message.
    RecipientsEditor *recipientsEditor() const;

    /// The content of the message.
    QString content() const;

    void addAttachment(const QList<AttachmentInfo> &infos, bool showWarning);

    void reply(const KMime::Message::Ptr &message);
    void forward(const KMime::Message::Ptr &message);
    void setMessage(const KMime::Message::Ptr &message);

private Q_SLOTS:
    void slotSend();
    void slotToggleMarkup();
    void slotSignToggled(bool on);
    void slotSaveDraft();
    void slotSaveAsFile();
    void slotInsertFile();
    void slotEncryptionButtonIconUpdate();
    void slotEditIdentity();
    void slotIdentityChanged();
    void slotPrint();
    void slotPrintPreview();
    void slotWordWrapToggled(bool on);
    void slotAutoSpellCheckingToggled(bool enabled);
    void slotSpellcheckConfig();
    void slotHandleError(const QString &errorMessage);
    void printInternal(QPrinter *printer);
    void enableHtml();
    void slotPasteAsAttachment();
    void disableHtml(Confirmation confirmation);
    void slotCursorPositionChanged();
    void slotInsertRecentFile(const QUrl &u);
    void slotRecentListFileClear();
    void slotRecipientEditorFocusChanged();
    void slotRecipientAdded(RecipientLineNG *line);
    void slotRecipientFocusLost(RecipientLineNG *line);
    void slotRecipientEditorLineAdded(RecipientLineNG *line);
    void slotRecipientLineIconClicked(RecipientLineNG *line);
    void slotCloseWindow();
    void insertUrls(const QMimeData *source, const QList<QUrl> &urlList);
    bool insertFromMimeData(const QMimeData *source, bool forceAttachment);
    QUrl insertFile();

    void addAttachment(const QString &name, KMime::Headers::contentEncoding cte, const QByteArray &data, const QByteArray &mimeType);

    /// Set whether the message will be signed.
    void setSigning(bool sign, bool setByUser = false);

    /// Set whether the message should be treated as modified or not.
    void setModified(bool modified);

    std::shared_ptr<Kleo::ExpiryChecker> expiryChecker();

Q_SIGNALS:
    void identityChanged();
    void initialized();

protected:
    friend ComposerWindowFactory;

    explicit ComposerWindow(const QString &fromAddress, const QString &name, const QByteArray &bearerToken, QWidget *parent = nullptr);

    void reset(const QString &fromAddress, const QString &name, const QByteArray &bearerToken);

    void closeEvent(QCloseEvent *event) override;

private:
    enum CryptoKeyState {
        NoState = 0,
        InProgress,
        KeyOk,
        NoKey,
        NoTrusted,
    };

    /// Ask for confirmation if the message was changed.
    [[nodiscard]] bool queryClose() override;

    void annotateRecipientEditorLineWithCryptoInfo(RecipientLineNG *line);
    void setupActions();
    void setupStatusBar(QWidget *w);
    void htmlToolBarVisibilityChanged(bool visible);
    void changeCryptoAction();
    void runKeyResolver();
    int validateLineWrapWidth() const;
    void disableWordWrap();
    void checkOwnKeyExpiry(const KIdentityManagementCore::Identity &ident);
    std::unique_ptr<Kleo::KeyResolverCore> fillKeyResolver();

    /// Returns true if the message was modified by the user.
    [[nodiscard]] bool isModified() const;

    /// Returns true if the composer content was modified by the user.
    [[nodiscard]] bool isComposerModified() const;

    /**
     * Returns true if the message will be signed.
     */
    [[nodiscard]] bool sign() const;

    Kleo::CryptoMessageFormat cryptoMessageFormat() const;

    KIdentityManagementCore::Identity mIdentity;
    QString mFrom;
    QWidget *const mMainWidget;
    // splitter between the headers area and the actual editor
    MessageComposer::ComposerViewBase *const mComposerBase;
    QSplitter *const mHeadersToEditorSplitter;
    QWidget *const mHeadersArea;
    QGridLayout *const mGrid;
    QLabel *const mLblFrom;
    QPushButton *const mButtonFrom;
    RecipientsEditor *const mRecipientEditor;
    QLabel *const mLblSubject;
    QLineEdit *const mEdtSubject;
    MessageComposer::RichTextComposerNg *const mRichTextComposer;
    TextCustomEditor::RichTextEditorWidget *const mRichTextEditorWidget;
    NearExpiryWarning *const mNearExpiryWarning;
    KMComposerGlobalAction *const mGlobalAction;
    EWSMessageDispatcher *const mMessageDispatcher;

    QLabel *mEdtFrom = nullptr;
    bool mForceDisableHtml = false;
    bool mLastIdentityHasSigningKey = false;
    bool mLastIdentityHasEncryptionKey = false;
    QAction *mEncryptAction = nullptr;
    QAction *mSignAction = nullptr;
    QAction *mAppendSignature = nullptr;
    QAction *mPrependSignature = nullptr;
    QAction *mInsertSignatureAtCursorPosition = nullptr;
    QAction *mSelectAll = nullptr;
    QAction *mFindText = nullptr;
    QAction *mFindNextText = nullptr;
    QAction *mReplaceText = nullptr;
    QLabel *mStatusbarLabel = nullptr;
    QLabel *mCursorLineLabel = nullptr;
    QLabel *mCursorColumnLabel = nullptr;
    KToggleAction *mMarkupAction = nullptr;
    std::shared_ptr<Kleo::ExpiryChecker> mExpiryChecker;

    bool mIsModified = false;
    bool mAcceptedSolution = false;
    KRecentFilesAction *mRecentAction = nullptr;
    KToggleAction *mWordWrapAction = nullptr;
    KToggleAction *mAutoSpellCheckingAction = nullptr;
    bool mLastSignActionState = false;
    std::shared_ptr<Kleo::KeyCache> mKeyCache;
    bool mLastEncryptActionState = false;
    QTimer *mRunKeyResolverTimer = nullptr;
};
