#pragma once
#include "Book.hpp"
#include <sqlite3.h>
#include <string>
#include <vector>
#include <mutex>
#include <optional>

/**
 * @brief Thin RAII wrapper around the SQLite database backing the library.
 *
 * The manager owns the connection, exposes a handful of high-level CRUD helpers,
 * and hides statement preparation / busy handling from the rest of the app.
 * All public member functions are thread-safe: a global mutex guards access so
 * background metadata extraction can update the database safely.
 */
class DatabaseManager {
public:
  /// Open (or create) the database stored at @p db_path.
  explicit DatabaseManager(std::string db_path);
  ~DatabaseManager();

  DatabaseManager(const DatabaseManager&) = delete;
  DatabaseManager& operator=(const DatabaseManager&) = delete;

  /// Create the books table if it does not exist; idempotent.
  void ensure_schema();

  /// Insert or replace an existing book row using the book's id as the key.
  bool upsert_book(const Book& b);
  /// Remove a book row by id; returns false if the row did not exist.
  bool remove_book(const std::string& id);
  /// Retrieve a single book by id.
  std::optional<Book> get_book(const std::string& id);
  /// Load every book currently stored in the database.
  std::vector<Book>   load_all_books();
  /// Add a tag to a book.
  bool add_tag_to_book(const std::string& book_id, const std::string& tag_name);
  /// Remove a tag from a book.
  bool remove_tag_from_book(const std::string& book_id, const std::string& tag_name);
  /// Get all tags for a book.
  std::vector<std::string> get_tags_for_book(const std::string& book_id);

private:
  static int busy_handler(void* /*opaque*/, int prev_sleep_ms);
  void prepare_statements();

  std::string db_path_;
  std::mutex mtx_;
  sqlite3* db_ = nullptr;

};
