/*
 * Copyright (c) 2014-2026 Patrizio Bekerle -- <patrizio@bekerle.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 * for more details.
 *
 */

#pragma once

#include <entities/note.h>
#include <libraries/qhotkey/QHotkey/qhotkey.h>
#include <services/webappclientservice.h>
#include <widgets/logwidget.h>

#include <QFileSystemWatcher>
#include <QMainWindow>
#include <QSystemTrayIcon>

#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
class XdgGlobalShortcutManager;
#endif

#include "entities/notehistory.h"

#define SORT_ALPHABETICAL 0
#define SORT_BY_LAST_CHANGE 1
#define ORDER_ASCENDING 0     // Qt::AscendingOrder // = 0
#define ORDER_DESCENDING 1    // Qt::DescendingOrder // = 1

namespace Ui {
class MainWindow;
}

class HtmlPreviewWidget;
class QMimeData;
class QActionGroup;
class QListWidgetItem;
class QFileSystemWatcher;
class QFileDialog;
class QEvent;
class QSystemTrayIcon;
class QPlainTextEdit;
class QTextEdit;
class QTextDocument;
class QLabel;
class QMenu;
class QPushButton;
class QFile;
class QToolBar;
class QTreeWidget;
class QTreeWidgetItem;
class QShortcut;
class Note;
class NoteFolder;
class Tag;
class ScriptingService;
class QScrollArea;
class QDockWidget;
class QComboBox;
class ActionDialog;
class TodoDialog;
class QPrinter;
class LogWidget;
class StoredImagesDialog;
class StoredAttachmentsDialog;
class IssueAssistantDialog;
class NoteHistory;
class NoteDiffDialog;
class UpdateService;
class FakeVimHandler;
class WebSocketServerService;
class McpService;
class QOwnNotesMarkdownTextEdit;
class CommandBar;
class WaitingSpinnerWidget;
class NoteFilePathLabel;
class NoteRelationScene;
struct TagHeader;

// Manager forward declarations
class SpellCheckManager;
class SystemTrayManager;
class ExportPrintManager;
class NoteEncryptionManager;
class DistractionFreeManager;
class NoteTabManager;
class AiToolbarManager;
class LayoutManager;
class TagManager;
class NoteOperationsManager;
class NoteIndexManager;
class SearchFilterManager;
class MediaInsertionManager;
class NavigationManager;
class NoteTreeManager;

// forward declaration because of "xxx does not name a type"
class TodoDialog;
class SettingsDialog;
class SettingsService;

class MainWindow : public QMainWindow {
    Q_OBJECT
    Q_PROPERTY(Note currentNote WRITE setCurrentNote MEMBER currentNote NOTIFY currentNoteChanged)

    friend struct FileWatchDisabler;
    friend class SpellCheckManager;
    friend class SystemTrayManager;
    friend class ExportPrintManager;
    friend class NoteEncryptionManager;
    friend class DistractionFreeManager;
    friend class NoteTabManager;
    friend class AiToolbarManager;
    friend class LayoutManager;
    friend class TagManager;
    friend class NoteOperationsManager;
    friend class NoteIndexManager;
    friend class SearchFilterManager;
    friend class MediaInsertionManager;
    friend class NavigationManager;
    friend class NoteTreeManager;

   Q_SIGNALS:
    void currentNoteChanged(Note &note);
    void log(LogWidget::LogType logType, QString text);
    void settingsChanged();

   public:
    enum CreateNewNoteOption {
        None = 0x0000,

        // use the name parameter as headline too
        UseNameAsHeadline = 0x0001,

        // places the cursor at the end of the note
        CursorAtEnd = 0x0002,

        // don't call loadNoteDirectoryList
        DisableLoadNoteDirectoryList = 0x0004,
    };

    enum NoteTreeWidgetItemType {
        NoteType = 1,
        FolderType = 2,
    };

    Q_DECLARE_FLAGS(CreateNewNoteOptions, CreateNewNoteOption)

    explicit MainWindow(QWidget *parent = nullptr);

    ~MainWindow();

    void triggerStartupMenuAction();

    void reloadOpenAiControls();

    void setCurrentNoteText(const QString &text);

    void setCurrentNote(Note note, bool updateNoteText = true, bool updateSelectedNote = true,
                        bool addPreviousNoteToHistory = true);

    void createNewNote(QString noteName = QString(), bool withNameAppend = true);

    void doSearchInNote(QString searchText);

    const Note &getCurrentNote();

    void createNewNote(QString name, QString text,
                       CreateNewNoteOptions options = CreateNewNoteOption::None);

    void openSettingsDialog(int page = 0, bool openScriptRepository = false);

    void applyDarkModeSettings();

    void restoreTrashedNoteOnServer(const QString &fileName, int timestamp);

    void showUpdateAvailableButton(const QString &version);

    void hideUpdateAvailableButton();

    void enableShowVersionsButton();

    void enableShowTrashButton();

    void showStatusBarMessage(const QString &message, const QString &symbol = QString(),
                              int timeout = 4000);

    void showStatusBarMessage(const QString &message, int timeout = 4000);

    void handleInsertingFromMimeData(const QMimeData *mimeData);

    QOwnNotesMarkdownTextEdit *activeNoteTextEdit();

    static MainWindow *instance();

    QList<QMenu *> menuList();

    QAction *findAction(const QString &objectName);

    void editEncryptedNote();

    void editEncryptedNoteAsync();

    void addCustomAction(const QString &identifier, const QString &menuText,
                         const QString &buttonText, const QString &icon,
                         bool useInNoteEditContextMenu = false, bool hideButtonInToolbar = false,
                         bool useInNoteListContextMenu = false);

    void addScriptingLabel(const QString &identifier, const QString &text = QString());

    void setScriptingLabelText(const QString &identifier, const QString &text);

    void preReloadScriptingEngine();

    void writeToNoteTextEdit(const QString &text);

    QString selectedNoteTextEditText();

    void linkTagNameToCurrentNote(const QString &tagName, bool linkToSelectedNotes = false);

    void loadNoteBookmarks();

    Q_INVOKABLE void reloadTagTree();

    Q_INVOKABLE void reloadNoteSubFolderTree();

    Q_INVOKABLE void buildNotesIndexAndLoadNoteDirectoryList(bool forceBuild = false,
                                                             bool forceLoad = false,
                                                             bool reloadTabs = true);

    QVector<Note> selectedNotes();

    bool jumpToNoteSubFolder(int noteSubFolderId);

    void selectNavigationItemAtPosition(int position);

    Q_INVOKABLE bool createNewNoteSubFolder(QString folderName = QString());

    QString getLogText();

    void turnOnDebugLogging();

    void openIssueAssistantDialog();

    Q_INVOKABLE void insertHtmlAsMarkdownIntoCurrentNote(QString html);

    void resetBrokenTagNotesLinkFlag();

    Q_INVOKABLE QString getLayoutUuid(const QString &layoutName);

    Q_INVOKABLE void reloadCurrentNoteByNoteId(bool updateNoteText = false);

    Q_INVOKABLE QStringList getLayoutUuidList();

    Q_INVOKABLE void setCurrentLayout(const QString &uuid);

    // Deprecated scripting aliases kept for existing user scripts.
    Q_INVOKABLE QString getWorkspaceUuid(const QString &layoutName) {
        return getLayoutUuid(layoutName);
    }

    Q_INVOKABLE QStringList getWorkspaceUuidList() { return getLayoutUuidList(); }

    Q_INVOKABLE void setCurrentWorkspace(const QString &uuid) { setCurrentLayout(uuid); }

    Q_INVOKABLE bool insertDataUrlAsFileIntoCurrentNote(const QString &dataUrl);

    class NoteSubFolderTree *noteSubFolderTree();

    void openTodoDialog(const QString &taskUid = QString());

    void openNextcloudDeckDialog(int cardId = -1, int boardId = -1);

    class QOwnNotesMarkdownTextEdit *noteTextEdit();

    void refreshNotePreview(bool force = false);

    Q_INVOKABLE bool removeNoteTab(int index) const;

    Q_INVOKABLE QList<int> getNoteTabNoteIdList() const;

    Q_INVOKABLE bool jumpToTag(int tagId);

    void enableOpenAiActivitySpinner(bool enable = true);

   protected:
    void changeEvent(QEvent *event) override;

    void closeEvent(QCloseEvent *event) override;

    bool eventFilter(QObject *obj, QEvent *event) override;

   public slots:
    void setCurrentNoteFromNoteId(const int noteId);

    void regenerateNotePreview();

    void forceRegenerateNotePreview();

    void storeUpdatedNotesToDisk();

    bool changeNoteFolder(const int noteFolderId, const bool forceChange = false);

    void allowNoteEditing();

    void disallowNoteEditing();

    void updateFileNavigationTab();

    void updateBacklinkNavigationTab();

    void setOptionalNavigationTabVisible(QWidget *tab, const QString &title, int preferredIndex,
                                         bool visible);

    void openSelectedNotesInTab();

    void openNoteInTab(const Note &note, bool forceNewTab = false);

    void openCurrentNoteInTab();

    Q_INVOKABLE void focusNoteTextEdit();

    void onNavigationWidgetPositionClicked(int position);
    void onFileNavigationWidgetPositionClicked(int position);

    void onNavigationWidgetHeadingRenamed(int position, const QString &oldText,
                                          const QString &newText);

    void updateBacklinksAfterHeadingRename(const QString &oldHeading, const QString &newHeading);

   private slots:

    void on_noteTextEdit_textChanged();

    void on_action_Quit_triggered();

    void quitApp();

    void notesDirectoryWasModified(const QString &str);

    void notesWereModified(const QString &str);

    void on_actionSet_Cloud_Folder_triggered();

    void on_searchLineEdit_textChanged(const QString &arg1);

    void on_action_Find_note_triggered();

    void on_searchLineEdit_returnPressed();

    void on_action_Remove_note_triggered();

    void on_actionAbout_QOwnNotes_triggered();

    void on_action_New_note_triggered();

    void onNotePreviewAnchorClicked(const QUrl &arg1);

    void on_actionCheck_for_updates_triggered();

    void on_actionReport_problems_or_ideas_triggered();

    void on_actionAlphabetical_triggered(bool checked);

    void on_actionBy_date_triggered(bool checked);

    void systemTrayIconClicked(QSystemTrayIcon::ActivationReason reason);

    void on_action_Settings_triggered();

    void on_actionShow_versions_triggered();

    void on_actionShow_trash_triggered();

    void on_actionSelect_all_notes_triggered();

    void on_actionSelect_enclosed_text_triggered();

    void jumpToWelcomeNote();

    void pasteMediaIntoNote();

    void on_actionInsert_text_link_triggered();

    void on_action_DuplicateText_triggered();

    void on_actionToggle_checkboxes_triggered();
    void on_actionCreate_ordered_list_triggered();
    void on_actionCreate_alphabetical_list_triggered();
    void on_actionCreate_unordered_list_triggered();
    void on_actionCreate_checkbox_list_triggered();
    void on_actionClear_list_formatting_triggered();
    void on_actionOrder_checkboxes_triggered();
    void on_actionIncrease_heading_depth_triggered();
    void on_actionDecrease_heading_depth_triggered();
    void on_actionCopy_code_block_triggered();

    void on_action_Back_in_note_history_triggered();

    void on_action_Forward_in_note_history_triggered();

    void on_action_Previous_heading_triggered();

    void on_action_Next_heading_triggered();

    void on_actionFold_all_headings_triggered();

    void on_actionUnfold_all_headings_triggered();

    void on_action_Shortcuts_triggered();

    void on_action_Knowledge_base_triggered();

    void on_actionInsert_current_time_triggered();

    void on_actionShow_Todo_List_triggered();

    void frequentPeriodicChecker();

    void on_action_Export_note_as_PDF_markdown_triggered();

    void on_action_Export_note_as_PDF_text_triggered();

    void on_action_Print_note_markdown_triggered();

    void on_action_Print_note_text_triggered();

    void on_actionInsert_image_triggered();

    void on_actionShow_changelog_triggered();

    static void openLocalUrl(QString urlString);

    void on_action_Find_text_in_note_triggered();

    void on_action_Encrypt_note_triggered();

    void on_actionDecrypt_note_triggered();

    void on_actionEdit_encrypted_note_triggered();

    void on_encryptedNoteTextEdit_textChanged();

    void on_action_Open_note_in_external_editor_triggered();

    void on_action_Export_note_as_markdown_triggered();

    void showEvent(QShowEvent *event) override;

    void on_actionGet_invloved_triggered();

    void gotoNoteBookmark(int slot = 0);

    void storeNoteBookmark(int slot = 0);

    void deleteNoteBookmark(int slot);

    void updateNoteBookmarkDisplay();

    void on_actionOpen_note_bookmark_dialog_triggered();

    void on_actionInsert_code_block_triggered();

    void on_actionInsert_checkbox_list_item_triggered();

    void on_actionNext_note_triggered();

    void on_actionPrevious_Note_triggered();

    void on_actionToggle_distraction_free_mode_triggered();

    void toggleDistractionFreeMode();

    void trackAction(QAction *action);

    void on_actionShow_toolbar_triggered(bool checked);

    void toolbarVisibilityChanged(bool visible);

    void dfmEditorWidthActionTriggered(QAction *action);

    void dragEnterEvent(QDragEnterEvent *e) override;

    void dropEvent(QDropEvent *e) override;

    void on_actionPaste_image_triggered();

    void on_actionShow_note_in_file_manager_triggered();

    void on_actionFormat_text_bold_triggered();

    void on_actionFormat_text_underline_triggered();

    void on_actionFormat_text_italic_triggered();

    void on_action_Increase_note_text_size_triggered();

    void on_action_Decrease_note_text_size_triggered();

    void on_action_Reset_note_text_size_triggered();

    void on_noteFolderComboBox_currentIndexChanged(int index);

    void on_tagLineEdit_returnPressed();

    void on_tagLineEdit_textChanged(const QString &arg1);

    void on_newNoteTagButton_clicked();

    void on_newNoteTagLineEdit_returnPressed();

    void on_newNoteTagLineEdit_editingFinished();

    void removeNoteTagClicked();

    void on_action_new_tag_triggered();

    void on_action_Reload_note_folder_triggered();

    void noteViewUpdateTimerSlot();

    void autoReadOnlyModeTimerSlot();

    void gitCommitCurrentNoteFolder();

    void noteTextSliderValueChanged(int value, bool force = false);

    void noteViewSliderValueChanged(int value, bool force = false);

    void on_tagTreeWidget_itemChanged(QTreeWidgetItem *item, int column);

    void on_tagTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);

    void on_tagTreeWidget_itemSelectionChanged();

    void on_tagTreeWidget_customContextMenuRequested(const QPoint pos);

    void moveSelectedTagsToTagId(int tagId);

    void tagSelectedNotesToTagId(int tagId);

    void on_actionReplace_in_current_note_triggered();

    void onBacklinkWidgetNoteClicked(int noteId, QString markdown);

    void startNavigationParser();

    void onNoteTextViewResize(QSize size, QSize oldSize);

    void on_actionAutocomplete_triggered();

    void restoreDistractionFreeMode();

    void on_actionSelect_note_folder_triggered();

    void on_actionReload_scripting_engine_triggered();

    void on_actionShow_log_triggered();

    void on_actionExport_preview_HTML_triggered();

    void hideNoteFolderComboBoxIfNeeded();

    void generateSystemTrayContextMenu();

    void reloadTodoLists();

    void showWindow();

    void on_actionOpen_IRC_Channel_triggered();

    void storeSavedSearch();

    void on_actionInsert_headline_from_note_filename_triggered();

    void on_actionUse_softwrap_in_note_editor_toggled(bool arg1);

    void on_actionShow_status_bar_triggered(bool checked);

    void on_noteTreeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);

    void on_noteTreeWidget_customContextMenuRequested(const QPoint pos);

    void on_noteTreeWidget_itemChanged(QTreeWidgetItem *item, int column);

    void onCurrentSubFolderChanged();

    void onMultipleSubfoldersSelected();

    void clearTagFilteringColumn();

    void on_noteSubFolderLineEdit_textChanged(const QString &arg1);

    void on_noteSubFolderLineEdit_returnPressed();

    void on_actionShare_note_triggered();

    void on_actionToggle_text_case_triggered();

    void on_actionMarkdown_cheatsheet_triggered();

    void on_actionStrike_out_text_triggered();

    void on_actionShow_menu_bar_triggered(bool checked);

    void moveSelectedNotesToNoteSubFolderId(int noteSubFolderId);

    void copySelectedNotesToNoteSubFolderId(int noteSubFolderId);

    void on_actionSplit_note_at_cursor_position_triggered();

    void onCustomActionInvoked(const QString &identifier);

    void on_actionDonate_triggered();

    void on_actionFind_notes_in_all_subfolders_triggered();

    void on_actionImport_notes_from_Evernote_triggered();

    void on_actionManage_stored_images_triggered();

    void on_actionGitter_triggered();

    void on_actionUnlock_panels_toggled(bool arg1);

    void on_actionStore_as_new_layout_triggered();

    void onLayoutComboBoxCurrentIndexChanged(int index);

    void onAiBackendComboBoxCurrentIndexChanged(int index);

    void onAiModelComboBoxCurrentIndexChanged(int index);

    void onAiModelGroupChanged(QAction *action);

    void on_actionRemove_current_layout_triggered();

    void on_actionRename_current_layout_triggered();

    void on_actionSwitch_to_previous_layout_triggered();

    void on_actionManage_layouts_triggered();

    void on_actionShow_all_panels_triggered();

    Q_SLOT void restoreCurrentLayout();

    void togglePanelVisibility(const QString &objectName);

    void toggleToolbarVisibility(const QString &objectName);

    void updateToolbarMenu();

    void on_actionFind_action_triggered();

    void on_actionRedo_action_triggered();

    void releaseDockWidgetSizes();

    void on_actionInsert_table_triggered();

    void on_actionInsert_block_quote_triggered();

    void on_actionSearch_text_on_the_web_triggered();

    void noteEditCursorPositionChanged();
    void noteEditTextChanged();

    void on_actionDelete_line_triggered();

    void on_actionDelete_word_triggered();

    void on_actionView_note_in_new_window_triggered();

    void on_actionSave_modified_notes_triggered();

    void enableNoteExternallyRemovedCheck();

    void on_actionAscending_triggered();

    void on_actionDescending_triggered();

    bool restoreActiveNoteHistoryItem();

    void on_actionShow_note_git_versions_triggered();

    void on_actionShow_note_git_versions_external_triggered();

    void on_tagTreeWidget_itemCollapsed(QTreeWidgetItem *item);

    void on_tagTreeWidget_itemExpanded(QTreeWidgetItem *item);

    void on_actionScript_repository_triggered();

    void on_actionScript_settings_triggered();

    void filterNotesByTag();

    void on_actionInsert_attachment_triggered();

    void on_actionAllow_note_editing_triggered(bool checked);

    void on_actionCheck_for_script_updates_triggered();

    void on_actionShow_local_trash_triggered();

    void on_actionJump_to_note_text_edit_triggered();

    void on_tagTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);

    void on_noteTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);

    void on_noteTreeWidget_itemSelectionChanged();

    void on_actionManage_stored_attachments_triggered();

    void on_noteOperationsButton_clicked();

    void on_actionImport_notes_from_text_files_triggered();

    void on_actionTelegram_triggered();

    void on_actionCopy_headline_triggered();

    void on_action_FormatTable_triggered();

    void on_navigationLineEdit_textChanged(const QString &arg1);

    void initWebSocketServerService();

    void initWebAppClientService();

    void reinitWebAppClientService();

    void initMcpService();

    void updateLocalTrashActionVisibility();

    void on_actionJump_to_note_list_panel_triggered();

    void on_actionJump_to_tags_panel_triggered();

    void on_actionJump_to_note_subfolder_panel_triggered();

    void on_actionActivate_context_menu_triggered();

    void on_actionImport_bookmarks_from_server_triggered();

    void on_actionElementMatrix_triggered();

    void on_actionToggle_fullscreen_triggered();

    void disableFullScreenMode();

    void moveSelectedNotesToFolder(const QString &destinationFolder);

    void copySelectedNotesToFolder(const QString &destinationFolder,
                                   const QString &noteFolderPath = QString());

    void on_actionTypewriter_mode_toggled(bool arg1);

    // Spellchecker actions
    void on_actionCheck_spelling_toggled(bool checked);

    void onLanguageChanged(QAction *action);

    void onSpellBackendChanged(QAction *action);

    void on_actionManage_dictionaries_triggered();

#ifdef LANGUAGETOOL_ENABLED
    void on_actionCheck_grammar_with_LanguageTool_toggled(bool checked);
#endif
#ifdef HARPER_ENABLED
    void on_actionCheck_grammar_with_Harper_toggled(bool checked);
#endif

    void on_noteTextEdit_modificationChanged(bool arg1);

    void on_encryptedNoteTextEdit_modificationChanged(bool arg1);

    void on_actionEditorWidthCustom_triggered();

    void on_actionShow_Hide_application_triggered();

    void on_noteEditTabWidget_currentChanged(int index);

    void on_noteEditTabWidget_tabCloseRequested(int index);

    void on_actionPrevious_note_tab_triggered();

    void on_actionNext_note_tab_triggered();

    void on_actionClose_current_note_tab_triggered();

    void on_actionNew_note_in_new_tab_triggered();

    void on_noteEditTabWidget_tabBarDoubleClicked(int index);

    void on_actionToggle_note_stickiness_of_current_tab_triggered();

    void on_noteEditTabWidget_tabBarClicked(int index);

    void showNoteEditTabWidgetContextMenu(const QPoint &point);

    void on_actionJump_to_navigation_panel_triggered();

    void on_actionInsert_note_link_triggered();

    void on_actionImport_notes_from_Joplin_triggered();

    void on_actionToggle_Always_on_top_triggered();

    void on_action_Load_Todo_Items_triggered();

    void on_actionInsert_Nextcloud_Deck_card_triggered();

    void on_actionCopy_path_to_note_to_clipboard_triggered();

    void on_actionMove_up_in_subfolder_list_triggered();

    void on_actionMove_down_in_subfolder_list_triggered();

    void on_actionMove_up_in_tag_list_triggered();

    void on_actionMove_down_in_tag_list_triggered();

    void on_actionEnable_AI_toggled(bool arg1);

    void on_navigationTabWidget_currentChanged(int index);

    void on_actionReattach_panels_triggered();

    void on_actionManage_Nextcloud_Deck_cards_triggered();

    void on_actionSend_clipboard_triggered();

    void on_actionSend_clipboard_as_text_triggered();

   public:
    /** Settings access **/
    static bool isInDistractionFreeMode();
    void setShowNotesFromAllNoteSubFolders(bool show);
    bool showNotesFromAllNoteSubFolders() const;
    bool doNoteEditingCheck();

    /** Manager accessors **/
   public:
    SpellCheckManager *spellCheckManager() const { return _spellCheckManager; }
    SystemTrayManager *systemTrayManager() const { return _systemTrayManager; }
    ExportPrintManager *exportPrintManager() const { return _exportPrintManager; }
    NoteEncryptionManager *noteEncryptionManager() const { return _noteEncryptionManager; }
    DistractionFreeManager *distractionFreeManager() const { return _distractionFreeManager; }
    NoteTabManager *noteTabManager() const { return _noteTabManager; }
    AiToolbarManager *aiToolbarManager() const { return _aiToolbarManager; }
    LayoutManager *layoutManager() const { return _layoutManager; }
    TagManager *tagManager() const { return _tagManager; }
    NoteOperationsManager *noteOperationsManager() const { return _noteOperationsManager; }
    NoteIndexManager *noteIndexManager() const { return _noteIndexManager; }
    SearchFilterManager *searchFilterManager() const { return _searchFilterManager; }
    MediaInsertionManager *mediaInsertionManager() const { return _mediaInsertionManager; }
    NavigationManager *navigationManager() const { return _navigationManager; }
    NoteTreeManager *noteTreeManager() const { return _noteTreeManager; }

    /** State accessors needed by managers **/
    bool closeEventWasFired() const { return _closeEventWasFired; }
    bool noteEditIsCentralWidget() const { return _noteEditIsCentralWidget; }
    bool noteSubFolderDockWidgetVisible() const { return _noteSubFolderDockWidgetVisible; }
    void setNoteSubFolderDockWidgetVisible(bool visible) {
        _noteSubFolderDockWidgetVisible = visible;
    }
    void setNoteViewNeedsUpdate(bool needsUpdate) { _noteViewNeedsUpdate = needsUpdate; }
    QDockWidget *noteEditDockWidget() const { return _noteEditDockWidget; }
    QDockWidget *notePreviewDockWidget() const { return _notePreviewDockWidget; }

    // Methods needed by managers (made public)
    void updateNoteTextEditReadOnly();
    void handleNoteTextChanged();
    void storeSettings();
    void storeCurrentLayout();
    void handleNoteSubFolderVisibility() const;
    Q_SLOT void updatePanelMenu();
    void updateWindowToolbar();
    void setNoteEditCentralWidgetEnabled(bool enabled);
    void centerAndResize();
    void filterNotes(bool searchForText = true);
    void setNoteTextFromNote(Note *note, bool updateNoteTextViewOnly = false,
                             bool ignorePreviewVisibility = false,
                             bool allowRestoreCursorPosition = false);
    void setDockWidgetVisible(const QString &objectName, bool visible);
    void restoreDockWidgetTitleBars();
    void updateJumpToActionsAvailability();

    /** Actions **/
   public:
    QAction *newNoteAction();
    QAction *reloadNoteFolderAction();
    QAction *insertTextLinkAction();
    QAction *insertNoteLinkAction();
    QAction *searchTextOnWebAction();
    QAction *pasteImageAction();
    QAction *autocompleteAction();
    QAction *splitNoteAtPosAction();
    QAction *selectEnclosedTextAction();
    QAction *findNoteAction();
    QAction *toggleCheckboxesAction();
    QAction *createOrderedListAction();
    QAction *createAlphabeticalListAction();
    QAction *createUnorderedListAction();
    QAction *createCheckboxListAction();
    QAction *clearListFormattingAction();
    QAction *orderCheckboxesAction();
    QAction *increaseHeadingDepthAction();
    QAction *decreaseHeadingDepthAction();
    QAction *copyCodeBlockAction();
    QList<QAction *> customTextEditActions();
    QString noteFoldingReference(const Note &note) const;

   public:
    /** export / print **/
    void printTextDocument(QTextDocument *textDocument,
                           bool useLightEditorSchemaForDarkSchema = false);
    void exportNoteAsPDF(QTextDocument *doc, bool useLightEditorSchemaForDarkSchema = false);

    int getMaxImageWidth() const;

   public:
    void clearNoteDirectoryWatcher();
    void updateNoteDirectoryWatcher();
    bool isNoteDiffDialogOpen();

   private:
    Ui::MainWindow *ui;
    QString notesPath;
    QFileSystemWatcher noteDirectoryWatcher;
    Note currentNote;
    QString _currentNoteTextHash;
    NoteDiffDialog *noteDiffDialog;
    UpdateService *updateService;
    bool showSystemTray;
    QSystemTrayIcon *trayIcon = nullptr;
    QDateTime currentNoteLastEdited;
    QDateTime _lastHeartbeat;
    bool notifyAllExternalModifications;
    int noteSaveIntervalTime;
    QTimer *noteSaveTimer;
    QTimer *_frequentPeriodicTimer;
    QTimer *_noteViewUpdateTimer = nullptr;
    QTimer *_autoReadOnlyModeTimer;
    QTimer *_gitCommitTimer;
    QTimer *_todoListTimer;
    bool _noteViewNeedsUpdate;
    NoteHistory noteHistory;
    QHash<int, NoteHistoryItem> noteBookmarks;
    QPushButton *_updateAvailableButton;
    QPushButton *_webAppStatusButton;
    NoteFilePathLabel *_noteFilePathLabel;
    QLabel *_noteEditLineNumberLabel;
    QLabel *_noteEditStatisticsLabel;
    QPushButton *_readOnlyButton;
    QToolBar *_formattingToolbar;
    QToolBar *_customActionToolbar;
    QToolBar *_insertingToolbar;
    QToolBar *_encryptionToolbar;
    QToolBar *_windowToolbar;
    QToolBar *_quitToolbar;
    bool _noteViewIsRegenerated;
    QHash<int, NoteHistoryItem> _activeNoteFolderNotePositions;
    bool _searchLineEditFromCompleter;
    bool _isNotesDirectoryWasModifiedDisabled;
    bool _isNotesWereModifiedDisabled;
    bool _isDefaultShortcutInitialized;
    QList<QShortcut *> _menuShortcuts;
    bool _showNotesFromAllNoteSubFolders;
    QVector<int> _buildNotesIndexBeforeNoteIdList;
    QVector<int> _buildNotesIndexBeforeNoteSubFolderIdList;
    QList<int> _buildNotesIndexAfterNoteIdList;
    QList<int> _buildNotesIndexAfterNoteSubFolderIdList;
    QScrollArea *_noteTagButtonScrollArea;
    QDockWidget *_taggingDockWidget;
    QDockWidget *_noteSubFolderDockWidget;
    QDockWidget *_noteSearchDockWidget;
    QDockWidget *_noteFolderDockWidget;
    QDockWidget *_noteListDockWidget;
    QDockWidget *_noteNavigationDockWidget;
    QDockWidget *_noteEditDockWidget = nullptr;
    QDockWidget *_noteTagDockWidget;
    QDockWidget *_notePreviewDockWidget;
    QDockWidget *_logDockWidget;
    QDockWidget *_scriptingDockWidget;
    QDockWidget *_noteGraphicsViewDockWidget;
    class LogWidget *_logWidget;
    QWidget *_taggingDockTitleBarWidget;
    QWidget *_noteSubFolderDockTitleBarWidget;
    QWidget *_noteSearchDockTitleBarWidget;
    QWidget *_noteFolderDockTitleBarWidget;
    QWidget *_noteListDockTitleBarWidget;
    QWidget *_noteNavigationDockTitleBarWidget;
    QWidget *_noteEditDockTitleBarWidget = nullptr;
    QWidget *_noteTagDockTitleBarWidget;
    QWidget *_notePreviewDockTitleBarWidget;
    QWidget *_logDockTitleBarWidget;
    QWidget *_scriptingDockTitleBarWidget;
    QWidget *_noteGraphicsViewDockTitleBarWidget;
    NoteRelationScene *_noteRelationScene;
    QFrame *_noteFolderDockWidgetFrame;
    bool _useNoteFolderButtons;
    bool _noteFolderDockWidgetWasVisible;
    bool _noteSubFolderDockWidgetVisible;
    bool _closeEventWasFired;
    ActionDialog *_actionDialog;
    CommandBar *_commandBar;
    TodoDialog *_todoDialog;
    IssueAssistantDialog *_issueAssistantDialog;
    StoredImagesDialog *_storedImagesDialog;
    StoredAttachmentsDialog *_storedAttachmentsDialog;
    bool _noteExternallyRemovedCheckEnabled;
    QList<QAction *> _noteTextEditContextMenuActions;
    QList<QAction *> _noteListContextMenuActions;
    QString _notePreviewHash;
    int _gitCommitInterval;
    bool _noteEditIsCentralWidget;
    bool _lastNoteSelectionWasMultiple;
    WebSocketServerService *_webSocketServerService;
    WebAppClientService *_webAppClientService;
    QString _webAppClientServiceSettingsKey;
    QStringList _webAppConnectedDevices;
    McpService *_mcpService;
    bool _brokenTagNoteLinksRemoved = false;

#ifdef USE_QLITEHTML
    HtmlPreviewWidget *_notePreviewWidget = nullptr;
#endif

    QList<QHotkey *> _globalShortcuts;
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    XdgGlobalShortcutManager *_xdgShortcutManager = nullptr;
#endif
    bool _scriptUpdateFound = false;
    QAction *_lastTriggeredAction = nullptr;
    quint64 _fileNavigationUpdateRequestId = 0;
    quint64 _backlinkNavigationUpdateRequestId = 0;

    // Manager instances
    SpellCheckManager *_spellCheckManager = nullptr;
    SystemTrayManager *_systemTrayManager = nullptr;
    ExportPrintManager *_exportPrintManager = nullptr;
    NoteEncryptionManager *_noteEncryptionManager = nullptr;
    DistractionFreeManager *_distractionFreeManager = nullptr;
    NoteTabManager *_noteTabManager = nullptr;
    AiToolbarManager *_aiToolbarManager = nullptr;
    LayoutManager *_layoutManager = nullptr;
    TagManager *_tagManager = nullptr;
    NoteOperationsManager *_noteOperationsManager = nullptr;
    NoteIndexManager *_noteIndexManager = nullptr;
    SearchFilterManager *_searchFilterManager = nullptr;
    MediaInsertionManager *_mediaInsertionManager = nullptr;
    NavigationManager *_navigationManager = nullptr;
    NoteTreeManager *_noteTreeManager = nullptr;

    void initTreeWidgets();

    void initNotePreviewAndTextEdits();

    void connectFileWatcher(bool delayed = false);

    void createSystemTrayIcon();

    void loadNoteDirectoryList();

    void readSettings();

    bool buildNotesIndex(int noteSubFolderId = 0, bool forceRebuild = false);

    QString selectCloudNotesFolder();

    void removeCurrentNote();

    void searchInNoteTextEdit(QString str);

    void searchForSearchLineTextInNoteTextEdit();

    int openNoteDiffDialog(Note changedNote);

    void loadNoteFolderListMenu();

    void storeRecentNoteFolder(const QString &addFolderName, const QString &removeFolderName);

    void removeSelectedNotes();

    void selectAllNotes();

    void updateCurrentFolderTooltip();

    void handleTextNoteLinking(int page = 0);

    void updateNoteTextFromDisk(Note note);

    void makeCurrentNoteFirstInNoteList();

    void readSettingsFromSettingsDialog(const bool isAppLaunch = false);
    void checkAiToolbarConfiguration(bool askToShowToolbar = true);

    void setCurrentNoteFromHistoryItem(const NoteHistoryItem &item);

    bool prepareExportNoteAsPDFPrinter(QPrinter *printer);

    void exportNoteAsPDF(QPlainTextEdit *textEdit);

    bool preparePrintNotePrinter(QPrinter *printer);

    void updateNoteEncryptionUI();

    void askForEncryptedNotePasswordIfNeeded(const QString &additionalText = QString());

    void showAppMetricsNotificationIfNeeded();

    void resetCurrentNote(bool goToTop = true);

    void setupNoteBookmarkShortcuts();

    void setupStatusBarWidgets();

    void setupWebAppStatusButton();
    void connectWebAppClientServiceSignals();
    void updateWebAppStatusButton();
    void updateWebAppConnectedDevices(const QStringList &deviceNames);
    void showWebAppStatusContextMenu(const QPoint &point);

    void gotoNextNote();

    void activateContextMenu();

    void gotoPreviousNote();

    void setDistractionFreeMode(const bool enabled = true);

    void changeDistractionFreeMode(const bool enabled);

    bool insertMedia(QFile *file, QString title = QString());

    static bool isValidMediaFile(QFile *file);

    static bool isValidNoteFile(QFile *file);

    void removeSelectedTags();

    void setupTags();

    void reloadCurrentNoteTags();

    void highlightCurrentNoteTagsInTagTree();

    void filterNotesBySearchLineEditText(bool searchInNote = true);

    bool isTagsEnabled();

    void initStyling();

    void tagSelectedNotes(const Tag &tag);

    static bool isMarkdownViewEnabled();

    void removeTagFromSelectedNotes(const Tag &tag);

    bool isNoteEditPaneEnabled();

    void initToolbars();

    void buildTagTreeForParentItem(QTreeWidgetItem *parent = nullptr, bool topLevel = false);

    void buildTagMoveMenuTree(QMenu *parentMenu, int parentTagId = 0);

    void buildBulkNoteTagMenuTree(QMenu *parentMenu, int parentTagId = 0);

    QTreeWidgetItem *addTagToTagTreeWidget(QTreeWidgetItem *parent, const TagHeader &tag);

    bool jumpToNoteName(const QString &name);

    bool jumpToNoteHistoryItem(const NoteHistoryItem &historyItem);

    void initScriptingEngine();

    void updateWindowTitle();

    void initSavedSearchesCompleter();

    void initEditorSoftWrap();

    bool isToolbarVisible();

    QTreeWidgetItem *firstVisibleNoteTreeWidgetItem();

    void setupNoteSubFolders();

    void filterNotesByNoteSubFolders();

    bool addNoteToNoteTreeWidget(const Note &note, QTreeWidgetItem *parent = nullptr);

    QTreeWidgetItem *findNoteInNoteTreeWidget(const Note &note);

    void jumpToNoteOrCreateNew(bool disableLoadNoteDirectoryList = false);

    void updateShareButton();

    void initShortcuts();

    void buildBulkNoteSubFolderMenuTree(QMenu *parentMenu, bool doCopy = true,
                                        int parentNoteSubFolderId = 0);

    void buildBulkNoteFolderSubFolderMenuTree(QMenu *parentMenu, bool doCopy,
                                              const QString &parentNoteSubFolderPath,
                                              bool isRoot = true);

    void moveSelectedNotesToNoteSubFolder(const NoteSubFolder &noteSubFolder);

    void copySelectedNotesToNoteSubFolder(const NoteSubFolder &noteSubFolder);

    void initTagButtonScrollArea();

    static QIcon getSystemTrayIcon();

    void initShowHidden();

    void initTreeWidgetItemHeight();

    static void updateTreeWidgetItemHeight(QTreeWidget *treeWidget, int height);

    void initDockWidgets();

    void createNoteEditDockWidget();

    void updateNoteEditFrameShape() const;

    void restoreToolbars();

    void initPanelMenu();

    void initToolbarMenu();

    void assignColorToTagItem(QTreeWidgetItem *item);

    void disableColorOfTagItem(QTreeWidgetItem *item);

    void assignColorToSelectedTagItems();

    void handleNoteTreeTagColoringForNote(const Note &note);

    bool showRestartNotificationIfNeeded(bool force = false);

    void unsetCurrentNote();

    void setNoteTextEditReadOnly(bool readonly) const;

    void updateNoteSortOrderSelectorVisibility(bool visible);

    int getSelectedNotesCount() const;

    void updateNoteTreeWidgetItem(const Note &note, QTreeWidgetItem *noteItem = nullptr);

    void updateNoteTreeWidgetItemIcon(const Note &note);

    void initFakeVim(QOwnNotesMarkdownTextEdit *noteTextEdit);

    void openNotesContextMenu(const QPoint globalPos, bool hasNotes = true,
                              bool hasFolders = false);

    void updateCurrentNoteTextHash();

    void removeConflictedNotesDatabaseCopies();

    void insertNoteText(const QString &text);

    QTextDocument *getDocumentForPreviewExport();

    void noteTextEditTextWasUpdated();
    void removeNoteFromNoteTreeWidget(Note &note) const;
    void initGlobalKeyboardShortcuts();
    void initX11GlobalShortcuts(SettingsService &settings, const QStringList &allKeys);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
    void initWaylandGlobalShortcuts(SettingsService &settings, const QStringList &allKeys);
#endif
    void resizeTagTreeWidgetColumnToContents() const;
    void updateCurrentTabData(const Note &note) const;
    bool jumpToTab(const Note &note) const;
    void closeOrphanedTabs() const;
    void automaticScriptUpdateCheck();
    int getNoteTabIndex(int noteId) const;
    bool startAutoReadOnlyModeIfEnabled();
    void updateActionUiEnabled();
    void setupNoteRelationScene();
    void updateNoteGraphicsView();
    bool noteDirectoryWatcherAddPath(const QString &path);
    void addDirectoryToDirectoryWatcher(const QString &path);
    bool nextCloudDeckCheck();

    // Methods that remain in mainwindow.cpp (delegated or full implementations)
    void startAppVersionTest();
    void initLayoutComboBox();
    void updateLayoutLists(bool rebuild = true);
    void initializeOpenAiActivitySpinner();
    void directoryWatcherWorkaround(bool isNotesDirectoryWasModifiedDisabled,
                                    bool alsoHandleNotesWereModified = false);
    bool insertTextAsAttachment(const QString &text);
    bool insertAttachment(QFile *file, const QString &title = QString(),
                          const QString &fileName = QString());
    bool undoFormatting(const QString &formatter);
    void applyFormatter(const QString &formatter);
    void handleScriptingNoteTagging(Note note, const Tag &tag, bool doRemove,
                                    bool triggerPostMethods = true);
    void handleScriptingNotesTagUpdating();
    void handleScriptingNotesTagRenaming(const Tag &tag, const QString &newTagName);
    void handleScriptingNotesTagRemoving(const Tag &tag, bool forBulkOperation = false);
    void selectAllNotesInNoteSubFolderTreeWidget() const;
    void selectAllNotesInTagTreeWidget() const;
    void handleDockWidgetLocking(QDockWidget *dockWidget);
    bool createNewLayout(QString name);
    QString currentLayoutUuid();
    void generateAiBackendComboBox();
    void generateAiModelMainMenu();
    void aiModelMainMenuSetCurrentItem();
    void generateAiModelComboBox();
    void storeTagTreeWidgetExpandState() const;
    void updatePanelsSortOrder();
    void updateNotesPanelSortOrder();
    void setMenuEnabled(QMenu *menu, bool enabled);
    void loadDictionaryNames();
    void loadSpellingBackends();
    void buildAiToolbarAndActions();
    void copyNoteFilenameToClipboardTriggered();
};
