#pragma once

#include <nlohmann/json.hpp>

#include <filesystem>
#include <mutex>
#include <optional>
#include <string>

struct sqlite3;

namespace lm {

class Database
{
public:
  explicit Database(std::filesystem::path data_dir);

  bool init(std::string& err);
  void close();

  std::filesystem::path dataDir() const { return data_dir_; }
  std::filesystem::path dbPath() const { return db_path_; }
  std::filesystem::path mapsDir() const { return data_dir_ / "maps"; }
  std::filesystem::path soundsDir() const { return data_dir_ / "sounds"; }
  std::filesystem::path recordingsDir() const { return data_dir_ / "recordings"; }

  bool getDocument(const std::string& name, nlohmann::json& out) const;
  bool setDocument(const std::string& name, const nlohmann::json& doc);

  std::optional<nlohmann::json> getLayoutProfile(const std::string& id) const;
  bool setLayoutProfile(const nlohmann::json& profile);
  bool deleteLayoutProfile(const std::string& id);

  sqlite3* handle() const { return db_; }

private:
  std::filesystem::path data_dir_;
  std::filesystem::path db_path_;
  sqlite3* db_ = nullptr;
  mutable std::mutex mu_;

  bool openDb(std::string& err);
  bool applySchema(std::string& err);
  bool applySchemaMigrations(std::string& err);
  bool migrateFromJsonIfNeeded(std::string& err);
  bool ensureDataDirs(std::string& err);
  bool migrateLegacyMapsDir(std::string& err);
  std::optional<std::string> getMeta(const std::string& key) const;
  bool setMeta(const std::string& key, const std::string& value);
};

}  // namespace lm
