#pragma once

#include "Book.hpp"
#include "DatabaseManager.hpp"

#include <vector>
#include <string>
#include <optional>
#include <mutex>
#include <sigc++/signal.h>

/**
 * @brief Thread-aware, signal-emitting container of @ref Book objects.
 *
 * BookList keeps an in-memory vector of books in sync with @ref DatabaseManager,
 * broadcasts fine-grained signals when the collection changes, and offers
 * helper methods that are safe to call from background threads (the *_enqueue
 * variants marshal work back onto the main loop).
 */
class BookList {
public:
	explicit BookList(DatabaseManager& database);

	// ---- Loading ----
	/// Load all rows from the database, replacing the in-memory vector.
	void loadAll();
	const std::vector<Book>& getBooks() const noexcept { return m_books; }
	std::size_t size() const noexcept { return m_books.size(); }

	// ---- CRUD ----
	/// Insert or update (by Book::id) and emit the relevant signal.
	bool upsert(const Book& book);
	/// Remove by id; returns false when the book was not present.
	bool removeById(const std::string& id);

	std::optional<Book> findById(const std::string& id) const;
	int indexOf(const std::string& id) const; // -1 if not found

	// ---- Bulk operations ----
	bool upsertMany(const std::vector<Book>& items);

	// ---- Worker-thread safe enqueue versions ----
	void upsertEnqueue(Book book);
	void removeByIdEnqueue(std::string id);
	void loadAllEnqueue();

	// ---- Signals ----
	/// Emitted after a new book enters the vector.
	sigc::signal<void(const Book&)>&          signalBookAdded()   { return m_signalBookAdded; }
	/// Emitted after a book already present changes.
	sigc::signal<void(const Book&)>&          signalBookUpdated() { return m_signalBookUpdated; }
	/// Emitted after a book is removed from the vector.
	sigc::signal<void(const std::string&)>&   signalBookRemoved() { return m_signalBookRemoved; }
	/// Emitted when the vector is cleared or reloaded wholesale.
	sigc::signal<void()>&                     signalReset()       { return m_signalReset; }
	/// Emitted after batch operations that significantly mutate the list.
	sigc::signal<void()>&                     signalBulkChanged() { return m_signalBulkChanged; }

private:
	DatabaseManager& m_database;
	std::vector<Book> m_books;
	mutable std::mutex m_mutex;

	int indexOfUnlocked(const std::string& id) const;

	// ---- Signals ----
	sigc::signal<void(const Book&)>          m_signalBookAdded;
	sigc::signal<void(const Book&)>          m_signalBookUpdated;
	sigc::signal<void(const std::string&)>   m_signalBookRemoved;
	sigc::signal<void()>                     m_signalReset;
	sigc::signal<void()>                     m_signalBulkChanged;
};
