#pragma once
// We use our own shortcut stuff by design, instead of using QShortcut and the likes.
#include <optional>
#include <vector>
#include <QChar>
#include <QStringView>
#include <QVariantList>
#include <qnamespace.h>
#include "keybind.hpp"

class QKeyEvent;

namespace Keyboard {
// Maps a non-Latin character key (e.g Cyrillic) to the Latin key at the same physical position,
// so recorded shortcuts stay layout-independent. Identity for Latin keys and non-macOS platforms.
Qt::Key normalizeToLatin(Qt::Key key);

// Typed character for keys whose Qt::Key value is its uppercase code point, nullopt for named keys.
std::optional<QChar> printableCharForKey(Qt::Key key);

std::optional<QString> stringForKey(Qt::Key key);
std::optional<Qt::Key> keyFromString(QStringView key);
std::optional<Qt::KeyboardModifier> modifierFromString(QStringView modifier);

class Shortcut {
public:
  static Shortcut osCopy() { return Shortcut(Qt::Key_C, Qt::ControlModifier); }
  static Shortcut osPaste() { return Shortcut(Qt::Key_V, Qt::ControlModifier); }
  static Shortcut enter() { return Qt::Key_Return; }
  static Shortcut submit() { return Shortcut(Qt::Key_Return, Qt::ControlModifier); }

  static Shortcut shiftPaste() { return osPaste().shifted(); }
  static Shortcut fromString(const QString &str) { return str; }
  static Shortcut fromKeyPress(const QKeyEvent &event);

  Shortcut() : m_isValid(false) {}
  Shortcut(Qt::Key key, Qt::KeyboardModifiers mods = {}) : m_key(key), m_modifiers(mods), m_isValid(true) {}
  Shortcut(const QKeyEvent *event);

  /**
   * Construct shortcut from a named keybind, which are application keybinds that are configurable by the user
   */
  Shortcut(Keybind bind);
  Shortcut(const QString &str);

  Qt::Key key() const { return m_key; }
  Qt::KeyboardModifiers mods() const { return m_modifiers; }
  bool hasMods() const { return mods().toInt() > 0; }

  Shortcut shifted() { return Shortcut(m_key, m_modifiers |= Qt::ShiftModifier); }

  bool isValid() const { return m_isValid; }
  operator bool() const { return isValid(); }

  std::vector<Qt::KeyboardModifier> modList() const;

  bool isValidKey() const { return stringForKey(m_key).has_value(); }
  bool isFunctionKey() const { return m_key >= Qt::Key_F1 && m_key <= Qt::Key_F24; }

  // The keyboard shortcut as a string.
  // This form is used to serialize shortcut data in config files/database.
  // It can be parsed back using Shortcut::fromString
  // e.g meta+shift+A
  QString toString() const;

  QString toBindingSequence() const;

  // Human-readable display form for UI badges (e.g. "Ctrl+B", "Shift+Enter")
  QString toDisplayString() const;
  QVariantList toDisplayTokens() const;
  Shortcut &modded(Qt::KeyboardModifier mod);

  bool equals(const Shortcut &other, bool ignoreNumpadMod = true) const;

  bool operator==(const Shortcut &other) const;

private:
  Qt::Key m_key = Qt::Key_unknown;
  Qt::KeyboardModifiers m_modifiers;
  bool m_isValid = false;
};

}; // namespace Keyboard
