#pragma once
#include "BookList.hpp"
#include "BookTile.hpp"

#include <gtkmm/scrolledwindow.h>
#include <gtkmm/gridview.h>
#include <gtkmm/singleselection.h>
#include <gtkmm/signallistitemfactory.h>
#include <gtkmm/gestureclick.h>
#include <gtkmm/eventcontrollermotion.h>
#include <giomm/liststore.h>

/**
 * @brief GridView-based widget that renders and filters the user's library.
 *
 * BookShelf mirrors the books held in @ref BookList into a Gio::ListStore,
 * drives a @ref Gtk::GridView factory to build @ref BookTile instances,
 * and exposes a fuzzy filtering API plus activation signal for the rest
 * of the UI.
 */
class BookShelf : public Gtk::ScrolledWindow {
public:
  explicit BookShelf(BookList& bookList, int coverSize = 128);

  // force rebuild (e.g., on reset)
  /// Recompute the visible grid contents from the backing model.
  void reload();

  // signal when a tile is activated (clicked)
  sigc::signal<void(const Book&)>& signalBookActivated() { return m_signalBookActivated; }
  /// Apply a fuzzy search query (empty string restores the full collection).
  void setFilter(const std::string& query);
  const std::string& filter() const noexcept { return m_filter; }
  bool empty() const noexcept;

private:
  // signal handlers
  void onBookAdded(const Book& b);
  void onBookUpdated(const Book& b);
  void onBookRemoved(const std::string& id);
  void onReset();

  // helpers
  void addTile(const Book&);
  void updateTile(const Book&);
  void removeTile(const std::string&);
  void onFactorySetup(const Glib::RefPtr<Gtk::ListItem>& item);
  void onFactoryBind(const Glib::RefPtr<Gtk::ListItem>& item);
  void onFactoryUnbind(const Glib::RefPtr<Gtk::ListItem>& item);
  void refreshVisible();

  class BookObject;
  BookList& m_bookList;
  int m_coverSize = 128;

  Glib::RefPtr<Gio::ListStore<BookObject>> m_store;
  Glib::RefPtr<Gtk::SingleSelection> m_selection;
  Gtk::GridView m_grid;
  Glib::RefPtr<Gtk::GestureClick> m_backgroundClick;
  Glib::RefPtr<Gtk::EventControllerMotion> m_motion;
  std::string m_filter;

  sigc::signal<void(const Book&)> m_signalBookActivated;
};
