// config-store, срез 02: каркас приложения
// Раздел учебника: Том I, глава 2, «Установка и первый запуск», §2.4 «Минимальный пример».
// Что добавляется по сравнению с предыдущим срезом: каркас конфигурационного
//   хранилища — открытие БД, команды set/get/del поверх главной таблицы.
//   Сквозной проект: по мере томов срез превращается в полноценное приложение.
// Сборка: g++ -std=c++17 -I<libmdbx-include> -I../common config-store-02.c++ -lmdbx
// Запуск: ./config-store-02 [set KEY VALUE | get KEY | del KEY]
//   без аргументов выполняется демонстрационный сценарий.
// Ожидаемый вывод (демо):
//   ok: set theme = dark
//   ok: set lang = ru
//   ok: theme = dark
//   ok: del lang
//   ok: config-store-02 works
// При сбое — сообщение в stderr и 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 {
    // демо всегда стартует с чистой БД
    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;
    }

    // Демонстрационный сценарий: мини-CLI над теми же командами.
    {
      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;
  }
}