#pragma once
#include "emoji/emoji.hpp"
#include "omni-database.hpp"
#include <qobject.h>
#include <unordered_set>
#include <string_view>
#include "fuzzy/scored.hpp"

/**
 * Provides all emoji-related services. Also integrates with the local sqlite database to provide
 * 'frequently used' metrics and all that.
 * The list of emojis is statically generated by a build script and is stored inside `emoji.cpp`.
 */

struct EmojiDataHash {
  size_t operator()(const EmojiData *data) { return std::hash<std::string_view>()(data->emoji); }
};

struct EmojiWithMetadata {
  const EmojiData *data = nullptr;
  uint32_t visitCount = 0;
  std::optional<QDateTime> pinnedAt;
  QString keywords;
};

class EmojiService : public QObject {
  Q_OBJECT

signals:
  void pinned(std::string_view emoji) const;
  void unpinned(std::string_view emoji) const;
  void visited(std::string_view emoji) const;
  void rankingReset(std::string_view emoji) const;

public:
  using GroupedEmojis = std::vector<std::pair<std::string_view, std::vector<const EmojiData *>>>;

  EmojiService(OmniDatabase &db);

  void loadKeywords();
  std::span<Scored<const EmojiData *>> search(std::string_view query) const;

  /**
   * List of emojis, ordered and grouped.
   */
  GroupedEmojis grouped();

  /**
   * Map metadata to the provided list of emojis.
   */
  std::vector<EmojiWithMetadata> mapMetadata(const std::vector<const EmojiData *> &items);
  EmojiWithMetadata mapMetadata(std::string_view emoji);

  std::vector<EmojiWithMetadata> getVisited() const;
  bool pin(std::string_view emoji);
  bool unpin(std::string_view emoji);
  bool registerVisit(std::string_view emoji);
  bool resetRanking(std::string_view emoji);

  /**
   * Set custom list of keywords to be searched in addition to the existing list.
   * It is provided as a single string which is then tokenized internally.
   */
  bool setCustomKeywords(std::string_view emoji, const QString &keywords);

private:
  void createDbEntry(std::string_view emoji);

  /**
   * Additional keywords set by the user
   */
  std::unordered_map<std::string, std::string> m_keywordMap;
  std::unordered_set<std::string_view> m_pinned;
  std::vector<Scored<const EmojiData *>> m_searchResults;

  OmniDatabase &m_db;
};
