#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "./passwordgeneratordialog.h"

#include <passwordfile/io/passwordfile.h>

#include <c++utilities/io/binaryreader.h>
#include <c++utilities/io/binarywriter.h>

#ifdef PASSWORD_MANAGER_SETUP_TOOLS_ENABLED
#include <qtutilities/setup/updater.h>
#endif

#include <QMainWindow>
#include <QMap>
#include <QTimer>

#include <memory>
#include <string_view>

QT_FORWARD_DECLARE_CLASS(QCloseEvent)
QT_FORWARD_DECLARE_CLASS(QTreeWidgetItem)
QT_FORWARD_DECLARE_CLASS(QUndoStack)
QT_FORWARD_DECLARE_CLASS(QUndoView)
QT_FORWARD_DECLARE_CLASS(QSettings)

#define PASSWORD_MANAGER_ENUM_CLASS enum class
namespace Io {
PASSWORD_MANAGER_ENUM_CLASS EntryType : int;
PASSWORD_MANAGER_ENUM_CLASS FieldType : int;
} // namespace Io
#undef PASSWORD_MANAGER_ENUM_CLASS

namespace QtUtilities {
class RecentMenuManager;
class AboutDialog;
class SettingsDialog;
class QtSettings;
} // namespace QtUtilities

namespace QtGui {

class FieldModel;
class EntryModel;
class EntryFilterModel;

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    explicit MainWindow(QSettings &settings, QtUtilities::QtSettings *qtSettings = nullptr, QWidget *parent = nullptr);
    ~MainWindow() override;

    QString selectedFieldsString() const;

public Q_SLOTS:
    // file management
    bool openFile(const QString &path);
    void createFile(const QString &path, const QString &password);
    void createFile(const QString &path);
    bool createFile();
    void changePassword();
    bool saveFile();
    void exportFile();
    bool closeFile();
    // show dialogs
    void showOpenFileDialog();
    void showSaveFileDialog();
    void showSettingsDialog();
    void showAboutDialog();
#ifdef PASSWORD_MANAGER_SETUP_TOOLS_ENABLED
    void showUpdaterDialog();
    void respawnIfRestartRequested();
#endif
    void showPassowrdGeneratorDialog();
    void showUndoView();

public:
    bool openFile(const QString &path, Io::PasswordFileOpenFlags openFlags); // can not be a slot in Qt 6 without further effort, see QTBUG-86424

protected:
    bool event(QEvent *event) override;
    bool eventFilter(QObject *obj, QEvent *event) override;
    void closeEvent(QCloseEvent *event) override;
    void timerEvent(QTimerEvent *event) override;

private Q_SLOTS:
    // file management
    bool showFile();
    // account/categories management
    void addAccount();
    void addCategory();
    void addEntry(Io::EntryType type);
    void removeEntry();
    void applyFilter(const QString &filterText);
    // row management
    void accountSelected(const QModelIndex &selected, const QModelIndex &);
    void insertRow();
    void insertTotpRow();
    void removeRows();
    void markAsPasswordField();
    void markAsNormalField();
    void setFieldType(Io::FieldType fieldType);
    void setPasswordVisibility(QAction *selectedAction);
    void insertFields(const QString &fieldsString);
    void copyFieldsForXMilliSeconds(int x = 5000);
    void copyFields();
    void copyFieldsTOTP();
    void copyTOTP(std::string url);
    void insertFieldsFromClipboard();
    // showing context menus
    void showTreeViewContextMenu(const QPoint &pos);
    void showTableViewContextMenu(const QPoint &pos);
    // other
    void showFileDetails();
    void showContainingDirectory();
    void clearClipboard();
    void setSomethingChanged();
    void setSomethingChanged(bool somethingChanged);
    void updateStyleSheet();
    void updateColumnSizing();
    void updateTotpStatus();

private:
    // showing conditional messages/prompts
    bool askForCreatingFile();
    bool showNoFileOpened();
    bool showNoAccount();
    // other
    void updateUiStatus();
    void updateWindowTitle();
    void applyDefaultExpanding(const QModelIndex &parent);
    Io::PasswordFileSaveFlags saveOptions() const;
    std::string_view selectedTotpUrl() const;

    std::unique_ptr<Ui::MainWindow> m_ui;
    Io::PasswordFile m_file;
    FieldModel *m_fieldModel;
    EntryModel *m_entryModel;
    EntryFilterModel *m_entryFilterModel;
    QUndoStack *m_undoStack;
    QUndoView *m_undoView;
    bool m_somethingChanged;
    Io::PasswordFileOpenFlags m_openFlags;
    bool m_dontUpdateSelection;
    int m_clearClipboardTimer;
    QTimer m_totpTimer;
    QtUtilities::RecentMenuManager *m_recentMgr;
    QtUtilities::AboutDialog *m_aboutDlg;
    QSettings &m_settings;
    QtUtilities::QtSettings *m_qtSettings;
    QtUtilities::SettingsDialog *m_settingsDlg;
#ifdef PASSWORD_MANAGER_SETUP_TOOLS_ENABLED
    QtUtilities::RestartHandler m_restartHandler;
    QtUtilities::UpdateDialog *m_updateSettingsDlg;
#endif
};

/*!
 * \brief Opens a file with the specified \a path and updates all widgets to show its contents.
 * \returns Returns true on success; otherwise false
 */
inline bool MainWindow::openFile(const QString &path)
{
    return openFile(path, Io::PasswordFileOpenFlags::Default);
}

#ifdef PASSWORD_MANAGER_SETUP_TOOLS_ENABLED
inline void MainWindow::respawnIfRestartRequested()
{
    m_restartHandler.respawnIfRestartRequested();
}
#endif

} // namespace QtGui

#endif // MAINWINDOW_H
