#ifndef LIBMONITARR_INCLUDE_DATA_DB_HPP_
#define LIBMONITARR_INCLUDE_DATA_DB_HPP_

#include "utils/config.hpp"

namespace monitarr {
struct data_entry final {
  std::string download_id;
  std::uint64_t last_check{};
  std::uint64_t size_left{};
};

class data_db final {
public:
  data_db() noexcept = default;
  data_db(const data_db &) noexcept = default;
  data_db(data_db &&) noexcept = default;

  auto operator=(const data_db &) noexcept -> data_db & = default;
  auto operator=(data_db &&) noexcept -> data_db & = default;

  ~data_db() noexcept;

private:
  std::shared_ptr<rocksdb::TransactionDB> db_;

private:
  [[nodiscard]] auto
  perform_action(std::string_view function_name,
                 std::function<rocksdb::Status(rocksdb::TransactionDB *tx_db)>
                     action) const -> bool;

  [[nodiscard]] auto perform_action(
      std::string_view function_name,
      std::function<rocksdb::Status(rocksdb::Transaction *txn)> action) -> bool;

public:
  void close();

  [[nodiscard]] auto get(std::string_view download_id) const
      -> std::optional<data_entry>;

  void open(std::string_view data_dir);

  void remove(std::string_view download_id);

  void set(const data_entry &entry);
};
} // namespace monitarr

NLOHMANN_JSON_NAMESPACE_BEGIN template <>
struct adl_serializer<monitarr::data_entry> {
  static void to_json(json &data, const monitarr::data_entry &value) {
    data["download_id"] = value.download_id;
    data["last_check"] = value.last_check;
    data["size_left"] = value.size_left;
  }

  static void from_json(const json &data, monitarr::data_entry &value) {
    data.at("download_id").get_to(value.download_id);
    data.at("last_check").get_to(value.last_check);
    data.at("size_left").get_to(value.size_left);
  }
};
NLOHMANN_JSON_NAMESPACE_END

#endif // LIBMONITARR_INCLUDE_DATA_DB_HPP_
