// config-store, slice 02: application skeleton
// Textbook section: Volume I, chapter 2, "Installation and first launch", §2.4 "Minimal example".
// What is added compared to the previous slice: the configuration store
//   skeleton — opening the DB, set/get/del commands over the main table.
//   End-to-end project: as the volumes progress, the slice becomes a full application.
// Build: g++ -std=c++17 -I<libmdbx-include> -I../common config-store-02.c++ -lmdbx
// Run: ./config-store-02 [set KEY VALUE | get KEY | del KEY]
//   without arguments a demo scenario is executed.
// Expected output (demo):
//   ok: set theme = dark
//   ok: set lang = ru
//   ok: theme = dark
//   ok: del lang
//   ok: config-store-02 works
// On failure — message to stderr and exit 1.
//
// SPDX-License-Identifier: Apache-2.0

#include <iostream>
#include <string>

#include "common.h++"
#include <mdbx.h++>

namespace {

const std::string db_path() { return std::string(example::tmpdir()) + "/config-store-02.mdbx"; }

void usage() { std::cerr << "usage: config-store-02 [set KEY VALUE | get KEY | del KEY]\n"; }

} // namespace

int main(int argc, char **argv) {
  try {
    // the demo always starts with a clean DB
    mdbx::env::remove(db_path());
    mdbx::env_managed env = example::env_open(db_path());

    if (argc >= 4 && std::string(argv[1]) == "set") {
      auto txn = env.start_write();
      auto table = txn.open_map(nullptr);
      txn.upsert(table, mdbx::slice(argv[2]), mdbx::slice(argv[3]));
      txn.commit();
      std::cout << "ok: set " << argv[2] << " = " << argv[3] << "\n";
      return EXIT_SUCCESS;
    }
    if (argc >= 3 && std::string(argv[1]) == "get") {
      auto rtxn = env.start_read();
      auto table = rtxn.open_map(nullptr);
      std::cout << rtxn.get(table, mdbx::slice(argv[2])).as_string() << "\n";
      rtxn.abort();
      return EXIT_SUCCESS;
    }
    if (argc >= 3 && std::string(argv[1]) == "del") {
      auto txn = env.start_write();
      auto table = txn.open_map(nullptr);
      if (!txn.erase(table, mdbx::slice(argv[2]))) {
        std::cerr << "no such key: " << argv[2] << "\n";
        return EXIT_FAILURE;
      }
      txn.commit();
      std::cout << "ok: del " << argv[2] << "\n";
      return EXIT_SUCCESS;
    }
    if (argc > 1) {
      usage();
      return EXIT_FAILURE;
    }

    // Demo scenario: a mini-CLI over the same commands.
    {
      auto txn = env.start_write();
      auto table = txn.open_map(nullptr);
      txn.upsert(table, mdbx::slice("theme"), mdbx::slice("dark"));
      txn.upsert(table, mdbx::slice("lang"), mdbx::slice("ru"));
      txn.commit();
    }
    std::cout << "ok: set theme = dark\n";
    std::cout << "ok: set lang = ru\n";
    {
      auto rtxn = env.start_read();
      auto table = rtxn.open_map(nullptr);
      std::cout << "ok: theme = " << rtxn.get(table, mdbx::slice("theme")).as_string() << "\n";
      rtxn.abort();
    }
    {
      auto txn = env.start_write();
      auto table = txn.open_map(nullptr);
      txn.erase(table, mdbx::slice("lang"));
      txn.commit();
    }
    std::cout << "ok: del lang\n";

    std::cout << "ok: config-store-02 works\n";
    return EXIT_SUCCESS;
  } catch (const std::exception &ex) {
    std::cerr << "error: " << ex.what() << "\n";
    return EXIT_FAILURE;
  }
}