#pragma once

#include <QTextEdit>

#include "helpers/qownnotesmarkdownhighlighter.h"
#include "libraries/qmarkdowntextedit/qmarkdowntextedit.h"
#include "services/markdownlspclient.h"
class MainWindow;
class QOwnSpellChecker;

#define QOWNNOTESMARKDOWNTEXTEDIT_OVERRIDE_FONT_SIZE_STYLESHEET_PRE_STRING \
    "/* BEGIN FONT SIZE OVERRIDE STYLESHEET */"
#define QOWNNOTESMARKDOWNTEXTEDIT_OVERRIDE_FONT_SIZE_STYLESHEET_POST_STRING \
    "/* END FONT SIZE OVERRIDE STYLESHEET */"

class QOwnNotesMarkdownTextEdit : public QMarkdownTextEdit {
    Q_OBJECT

   public:
    enum EditorWidthMode { Narrow = 1, Medium, Wide, Full, Custom };
    Q_ENUMS(EditorWidthMode)

    enum FontModificationMode { Increase = 1, Decrease, Reset };
    Q_ENUMS(FontModificationMode)

    explicit QOwnNotesMarkdownTextEdit(QWidget *parent = nullptr);
    ~QOwnNotesMarkdownTextEdit() override;

    void setStyles();
    void openUrl(const QString &urlString, bool openInNewTab) override;
    //    void setViewportMargins(int left, int top, int right, int bottom);
    void setPaperMargins(int width = -1);
    int modifyFontSize(FontModificationMode mode);
    void updateSettings();
    QMargins viewportMargins();
    void setText(const QString &text);
    static void setSpellCheckingEnabled(bool enabled);
    bool isSpellCheckingEnabled();
    void disableSpellChecking();
    bool usesMonospacedFont();

    /**
     * Toggles the case of the word under the Cursor or the selected text
     */
    void toggleCase();

    /**
     * Register this editor as the active one for AI autocomplete
     */
    void registerAsActiveEditor();

    /**
     * Unregister this editor from receiving AI autocomplete
     */
    void unregisterAsActiveEditor();

    /**
     * Get the currently active editor for AI autocomplete
     */
    static QOwnNotesMarkdownTextEdit *getActiveEditorForAutocomplete();

    /**
     * Inserts an empty code block
     */
    void insertCodeBlock();

    /**
     * Handles auto completion
     */
    void onAutoCompleteRequested();

    /**
     * Tries to find an equation in the current line and solves it
     * @return true on success
     */
    bool solveEquation(double &returnValue);

    /**
     * Inserts a block quote character or formats the selected text as block quote
     */
    void insertBlockQuote();

    /**
     * Returns the text from the current cursor to the start of the word in the
     * note text edit
     *
     * @param withPreviousCharacters also get more characters at the beginning
     *                               to get characters like "@" that are not
     *                               word-characters
     * @return
     */
    QString currentWord(bool withPreviousCharacters = false) const;

    /**
     * Tries to find words that start with the current word in the note text edit
     *
     * @param resultList
     * @return
     */
    bool autoComplete(QStringList &resultList) const;

    QString currentBlock() const;

    QSize minimumSizeHint() const;

    void updateIgnoredClickUrlRegexps();

    void setMarkdownLspDocumentPath(const QString &filePath, const QString &text);
    void closeMarkdownLspDocument();

   public slots:
    /**
     * Called when AI autocomplete is completed
     */
    void onAiAutocompleteCompleted(const QString &result);

    /**
     * Called when AI autocomplete request times out or errors
     */
    void onAiAutocompleteTimeout(const QString &errorString);

   protected:
    // we must not override _highlighter or Windows will create a
    // QOwnNotesMarkdownHighlighter and MarkdownHighlighter instance
    //    QOwnNotesMarkdownHighlighter *_highlighter;
    bool canInsertFromMimeData(const QMimeData *source) const override;
    void insertFromMimeData(const QMimeData *source) override;
    void resizeEvent(QResizeEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    bool eventFilter(QObject *obj, QEvent *event) override;
    void keyPressEvent(QKeyEvent *e) override;
    void focusInEvent(QFocusEvent *e) override;
    bool viewportEvent(QEvent *event) override;

   private:
    /// @param in is true if zoom-in, false otherwise
    void onZoom(bool in);

    void setFormatStyle(MarkdownHighlighter::HighlighterState index);

    void onContextMenu(QPoint pos);

    void overrideFontSizeStyle(int fontSize);

    QMenu *spellCheckContextMenu(QPoint pos);

    /**
     * Requests AI autocomplete for the current text
     */
    void requestAiAutocomplete();

    /**
     * Shows the AI autocomplete suggestion
     */
    void showAiAutocompleteSuggestion(const QString &suggestion);

    /**
     * Hides/clears the AI autocomplete suggestion
     */
    void clearAiAutocompleteSuggestion();

    /**
     * Accepts the current AI autocomplete suggestion
     */
    void acceptAiAutocompleteSuggestion();

    void applyMarkdownLspSettings();
    void scheduleMarkdownLspChange();
    void sendMarkdownLspChange();
    void showMarkdownLspCompletions(int requestId, const QStringList &items);
    void showMarkdownLspDiagnostics(const QString &uri,
                                    const QVector<MarkdownLspClient::Diagnostic> &diagnostics);
    void applyMarkdownLspDiagnosticsSelections();
    void applyMarkdownLspTextEdits(const QVector<MarkdownLspClient::TextEdit> &edits);
    void applyMarkdownLspFormatting(int requestId,
                                    const QVector<MarkdownLspClient::TextEdit> &edits);
    void requestMarkdownLspFormatting(bool useSelection);
    void requestMarkdownLspCodeActions(const QTextCursor &cursor);
    void showMarkdownLspCodeActions(int requestId,
                                    const QVector<MarkdownLspClient::CodeAction> &actions);
    void paintMarkdownImagePreviews();

    bool _isSpellCheckingDisabled = false;
    bool _showMarkdownImagePreviews = true;
    QString _aiAutocompleteSuggestion;
    int _aiAutocompletePosition = -1;
    QTimer *_aiAutocompleteTimer = nullptr;
    bool _isInsertingAiSuggestion = false;

    MarkdownLspClient *_markdownLspClient = nullptr;
    QTimer *_markdownLspChangeTimer = nullptr;
    QString _markdownLspUri;
    QString _markdownLspPendingText;
    int _markdownLspVersion = 0;
    int _markdownLspCompletionRequestId = -1;
    int _markdownLspFormattingRequestId = -1;
    int _markdownLspRangeFormattingRequestId = -1;
    int _markdownLspCodeActionRequestId = -1;
    bool _markdownLspApplyingEdits = false;
    QVector<MarkdownLspClient::Diagnostic> _markdownLspDiagnostics;
    QVector<MarkdownLspClient::CodeAction> _markdownLspLastCodeActions;
    bool _markdownLspEnabled = false;
    QList<QTextEdit::ExtraSelection> _markdownLspDiagnosticsSelections;

    // Static pointer to the currently active editor for AI autocomplete
    static QOwnNotesMarkdownTextEdit *_activeAutocompleteEditor;
};
