#include "config.hpp"
#include "connection.hpp"
#include "connection_handler.hpp"
#include "server.hpp"

#include <doctest/doctest.h>
#include <latch>
#include <string_view>
#include <thread>

// Helper to copy a string into arena memory
static std::string_view arena_copy_string(std::string_view str, Arena &arena) {
  if (str.empty()) {
    return std::string_view{};
  }
  char *copied = arena.allocate<char>(str.size());
  std::memcpy(copied, str.data(), str.size());
  return std::string_view(copied, str.size());
}

struct EchoHandler : ConnectionHandler {
  Arena arena;
  std::span<std::string_view> reply;
  WeakRef<MessageSender> wconn;
  std::latch done{1};
  void on_data_arrived(std::string_view data, Connection &conn) override {
    reply = std::span{arena.allocate<std::string_view>(1), 1};
    reply[0] = arena_copy_string(data, arena);
    wconn = conn.get_weak_ref();
    CHECK(wconn.lock());
    done.count_down();
  }
};

TEST_CASE("Echo test") {
  EchoHandler handler;
  weaseldb::Config config;
  config.server.io_threads = 1;
  auto server = Server::create(config, handler, {});
  int fd = server->create_local_connection();

  auto runThread = std::thread{[&]() { server->run(); }};

  int w = write(fd, "hello", 5);
  REQUIRE(w == 5);

  handler.done.wait();
  if (auto conn = handler.wconn.lock()) {
    conn->append_message(std::exchange(handler.reply, {}),
                         std::move(handler.arena));
  } else {
    REQUIRE(false);
  }

  char buf[6];
  buf[5] = 0;
  int r = read(fd, buf, 5);
  REQUIRE(r == 5);
  CHECK(std::string(buf) == "hello");

  close(fd);

  server->shutdown();
  runThread.join();
}
