#pragma once
#include "common/context.hpp"
#include "image-url.hpp"
#include <QObject>
#include <QQmlApplicationEngine>
#include <QTimer>
#include <QRect>
#include <qtmetamacros.h>

class ActionPanelController;
class AlertModel;
class ConfigBridge;
class GlobalShortcutBridge;
class HudBridge;
class ImageSource;
class KeybindBridge;
class KeyboardBridge;
class PlatformBridge;
class ThemeBridge;
class ViewHostBase;
class QQuickWindow;
class BaseView;
class DialogContentWidget;

class LauncherWindow : public QObject {
  Q_OBJECT
  Q_PROPERTY(bool atRoot READ atRoot NOTIFY atRootChanged)
  Q_PROPERTY(bool showBackButton READ showBackButton NOTIFY showBackButtonChanged)
  Q_PROPERTY(QString searchPlaceholder READ searchPlaceholder NOTIFY searchPlaceholderChanged)
  Q_PROPERTY(QUrl searchAccessoryUrl READ searchAccessoryUrl NOTIFY searchAccessoryChanged)
  Q_PROPERTY(QObject *commandViewHost READ commandViewHost NOTIFY commandViewHostChanged)
  Q_PROPERTY(QString navigationTitle READ navigationTitle NOTIFY navigationStatusChanged)
  Q_PROPERTY(ImageUrl navigationIcon READ navigationIcon NOTIFY navigationStatusChanged)
  Q_PROPERTY(bool toastActive READ toastActive NOTIFY toastActiveChanged)
  Q_PROPERTY(QString toastTitle READ toastTitle NOTIFY toastChanged)
  Q_PROPERTY(QString toastMessage READ toastMessage NOTIFY toastChanged)
  Q_PROPERTY(int toastStyle READ toastStyle NOTIFY toastChanged)
  Q_PROPERTY(AlertModel *alertModel READ alertModel CONSTANT)
  Q_PROPERTY(bool isLoading READ isLoading NOTIFY isLoadingChanged)
  Q_PROPERTY(bool searchVisible READ searchVisible NOTIFY searchVisibleChanged)
  Q_PROPERTY(bool searchInteractive READ searchInteractive NOTIFY searchInteractiveChanged)
  Q_PROPERTY(bool statusBarVisible READ statusBarVisible NOTIFY statusBarVisibleChanged)
  Q_PROPERTY(bool compacted READ compacted NOTIFY compactedChanged)
  Q_PROPERTY(bool hasCompleter READ hasCompleter NOTIFY completerChanged)
  Q_PROPERTY(bool popOnBackspace READ popOnBackspace)
  Q_PROPERTY(QVariantList completerArgs READ completerArgs NOTIFY completerChanged)
  Q_PROPERTY(QString completerIcon READ completerIcon NOTIFY completerChanged)
  Q_PROPERTY(QVariantList completerValues READ completerValues NOTIFY completerValuesChanged)
  Q_PROPERTY(int overrideWidth READ overrideWidth NOTIFY windowSizeOverrideChanged)
  Q_PROPERTY(int overrideHeight READ overrideHeight NOTIFY windowSizeOverrideChanged)
  Q_PROPERTY(bool hasOverlay READ hasOverlay NOTIFY overlayChanged)
  Q_PROPERTY(QUrl overlayUrl READ overlayUrl NOTIFY overlayChanged)
  Q_PROPERTY(QObject *overlayHost READ overlayHost NOTIFY overlayChanged)
  Q_PROPERTY(int lsLayer READ lsLayer NOTIFY lsChanged)
  Q_PROPERTY(int lsKeyboardInteractivity READ lsKeyboardInteractivity NOTIFY lsChanged)
  Q_PROPERTY(bool canPositionWindow READ canPositionWindow CONSTANT)

public:
  explicit LauncherWindow(ApplicationContext &ctx, QObject *parent = nullptr);

  bool atRoot() const { return m_atRoot; }
  bool showBackButton() const { return m_showBackButton; }
  QString searchPlaceholder() const { return m_searchPlaceholder; }
  QUrl searchAccessoryUrl() const { return m_searchAccessoryUrl; }
  QObject *commandViewHost() const { return m_commandViewHost; }

  QString navigationTitle() const { return m_navigationTitle; }
  ImageUrl navigationIcon() const { return m_navigationIcon; }
  bool toastActive() const { return m_toastActive; }
  QString toastTitle() const { return m_toastTitle; }
  QString toastMessage() const { return m_toastMessage; }
  int toastStyle() const { return m_toastStyle; }
  AlertModel *alertModel() const { return m_alertModel; }
  bool isLoading() const { return m_isLoading; }
  bool searchVisible() const { return m_searchVisible; }
  bool searchInteractive() const { return m_searchInteractive; }
  bool statusBarVisible() const { return m_statusBarVisible; }
  bool compacted() const { return m_compacted; }
  bool hasCompleter() const { return m_hasCompleter; }
  bool popOnBackspace();
  QVariantList completerArgs() const { return m_completerArgs; }
  QString completerIcon() const { return m_completerIcon; }
  QVariantList completerValues() const { return m_completerValues; }
  int overrideWidth() const { return m_overrideWidth; }
  int overrideHeight() const { return m_overrideHeight; }
  bool hasOverlay() const { return m_hasOverlay; }
  QUrl overlayUrl() const { return m_overlayUrl; }
  QObject *overlayHost() const { return m_overlayHost; }
  int lsLayer() const { return m_lsLayer; }
  int lsKeyboardInteractivity() const { return m_lsKeyboardInteractivity; }
  static bool canPositionWindow();

  Q_INVOKABLE void expand();
  Q_INVOKABLE void forwardSearchText(const QString &text);
  Q_INVOKABLE bool forwardKey(int key, int modifiers = 0);
  Q_INVOKABLE void handleEscape();
  Q_INVOKABLE void goBack();
  Q_INVOKABLE void popToRoot();
  Q_INVOKABLE void setCompleterValue(int index, const QString &value);
  Q_INVOKABLE QRect cursorScreenGeometry() const;
  Q_INVOKABLE void positionOnCursorScreen();
  Q_INVOKABLE void openFooterMenu();

signals:
  void compactedChanged();
  void atRootChanged();
  void showBackButtonChanged();
  void searchPlaceholderChanged();
  void searchAccessoryChanged();
  void commandViewHostChanged();
  void searchTextUpdated(const QString &text);
  void viewNavigatedBack();
  void commandViewPushed(const QUrl &componentUrl, const QVariantMap &properties);
  void commandViewReplaced(const QUrl &componentUrl, const QVariantMap &properties);
  void commandViewPopped();
  void navigationStatusChanged();
  void toastActiveChanged();
  void toastChanged();
  void isLoadingChanged();
  void searchVisibleChanged();
  void searchInteractiveChanged();
  void statusBarVisibleChanged();
  void completerChanged();
  void completerValuesChanged();
  void completerValidationFailed();
  void windowSizeOverrideChanged();
  void overlayChanged();
  void lsChanged();

private:
  bool eventFilter(QObject *obj, QEvent *event) override;
  void handleVisibilityChanged(bool visible);
  void handleCurrentViewChanged();
  void handleViewPoped(const BaseView *view);
  void updateWindowTitle();
  void applyPendingWindowTitle(int framesRemaining);
  void setCompacted(bool value);
  void tryCompaction();
  void applyWindowConfig();
  bool isLayerShellActive() const;
  void setExclusiveFocus(bool exclusive);
  void updateLayerShellProps();
  void buildFooterMenu();

  ApplicationContext &m_ctx;
  ActionPanelController *m_actionPanel;
  ActionPanelController *m_footerPanel;
  AlertModel *m_alertModel = nullptr;
  ConfigBridge *m_configBridge;
  ImageSource *m_imgSource;
  KeybindBridge *m_keybindProxy;
  KeyboardBridge *m_keyboardBridge;
  GlobalShortcutBridge *m_globalShortcutBridge;
  PlatformBridge *m_platformBridge;
  ThemeBridge *m_themeBridge;

  QQmlApplicationEngine m_engine;
  QQuickWindow *m_window = nullptr;
  QString m_defaultWindowTitle;
  QString m_pendingWindowTitle;
  bool m_compacted = false;
  bool m_atRoot = true;
  bool m_showBackButton = true;
  bool m_isLoading = false;
  bool m_searchVisible = true;
  bool m_searchInteractive = true;
  bool m_statusBarVisible = true;
  bool m_viewWasPopped = false;
  bool m_viewWasReplaced = false;
  bool m_pendingLauncherFileChoice = false;
  QString m_searchPlaceholder;
  QUrl m_searchAccessoryUrl;
  QMetaObject::Connection m_searchAccessoryConnection;
  QObject *m_commandViewHost = nullptr;

  QString m_navigationTitle;
  ImageUrl m_navigationIcon;

  bool m_toastActive = false;
  QString m_toastTitle;
  QString m_toastMessage;
  int m_toastStyle = 0;

  HudBridge *m_hudBridge = nullptr;

  int m_overrideWidth = 0;
  int m_overrideHeight = 0;
  bool m_hasOverlay = false;
  QUrl m_overlayUrl;
  QObject *m_overlayHost = nullptr;

  QTimer m_cacheEvictionTimer;
  bool m_closeOnFocusLoss = false;
  int m_lsLayer = 2;                 // LayerShellQt::Window::LayerTop
  int m_lsKeyboardInteractivity = 2; // LayerShellQt::Window::KeyboardInteractivityOnDemand
  bool m_hasCompleter = false;
  QVariantList m_completerArgs;
  QString m_completerIcon;
  QVariantList m_completerValues;
};
