cmake_minimum_required(VERSION 3.20)
project(weaseldb VERSION 0.0.1)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE Release)
endif()

set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
set(CMAKE_CXX_FLAGS_RELEASE
    "-g -O3 -Wall -Wextra -DNDEBUG -fno-omit-frame-pointer")

add_subdirectory(third_party)

find_package(Threads REQUIRED)

include(FetchContent)
FetchContent_Declare(
  toml11
  GIT_REPOSITORY https://github.com/ToruNiina/toml11.git
  GIT_TAG be08ba2be2a964edcdb3d3e3ea8d100abc26f286 # v4.4.0
)
FetchContent_MakeAvailable(toml11)

FetchContent_Declare(
  doctest
  GIT_REPOSITORY https://github.com/doctest/doctest.git
  GIT_TAG 1da23a3e8119ec5cce4f9388e91b065e20bf06f5 # v2.4.12
)
FetchContent_MakeAvailable(doctest)

FetchContent_Declare(
  nanobench
  GIT_REPOSITORY https://github.com/martinus/nanobench.git
  GIT_TAG a5a50c2b33eea2ff1fcb355cacdface43eb42b25 # v4.3.11
)
FetchContent_MakeAvailable(nanobench)

FetchContent_Declare(
  nlohmann_json
  GIT_REPOSITORY https://github.com/nlohmann/json.git
  GIT_TAG bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d # v3.11.2
)
FetchContent_MakeAvailable(nlohmann_json)

set(RAPIDJSON_BUILD_TESTS
    OFF
    CACHE BOOL "Disable RapidJSON tests" FORCE)
FetchContent_Declare(
  RapidJSON
  GIT_REPOSITORY https://github.com/Tencent/rapidjson.git
  GIT_TAG ab1842a2dae061284c0a62dca1cc6d5e7e37e346 # v1.1.0
)
FetchContent_MakeAvailable(RapidJSON)

set(SIMDUTF_TESTS
    OFF
    CACHE BOOL "Disable simdutf tests" FORCE)
set(SIMDUTF_BENCHMARKS
    OFF
    CACHE BOOL "Disable simdutf benchmarks" FORCE)
set(SIMDUTF_TOOLS
    OFF
    CACHE BOOL "Disable simdutf tools" FORCE)
FetchContent_Declare(
  simdutf
  GIT_REPOSITORY https://github.com/simdutf/simdutf.git
  GIT_TAG 6aacd743d20528a2082189504ac96caf749e6c2e # v7.3.6
)
FetchContent_MakeAvailable(simdutf)

FetchContent_Declare(
  llhttp
  URL "https://github.com/nodejs/llhttp/archive/refs/tags/release/v9.2.1.tar.gz"
  URL_HASH
    SHA256=3c163891446e529604b590f9ad097b2e98b5ef7e4d3ddcf1cf98b62ca668f23e
  DOWNLOAD_EXTRACT_TIMESTAMP ON)
set(BUILD_SHARED_LIBS
    OFF
    CACHE INTERNAL "")
set(BUILD_STATIC_LIBS
    ON
    CACHE INTERNAL "")
FetchContent_MakeAvailable(llhttp)

include_directories(src)

find_package(weaseljson REQUIRED)

# Generate JSON token hash table using gperf
find_program(GPERF_EXECUTABLE gperf REQUIRED)
add_custom_command(
  OUTPUT ${CMAKE_BINARY_DIR}/json_tokens.cpp
  COMMAND
    ${GPERF_EXECUTABLE} --class-name=PerfectHash
    ${CMAKE_SOURCE_DIR}/src/json_tokens.gperf >
    ${CMAKE_BINARY_DIR}/json_tokens.cpp
  DEPENDS ${CMAKE_SOURCE_DIR}/src/json_tokens.gperf
  COMMENT "Generating JSON token hash table with gperf")
add_custom_target(generate_json_tokens
                  DEPENDS ${CMAKE_BINARY_DIR}/json_tokens.cpp)

set(SOURCES
    src/main.cpp
    src/config.cpp
    src/connection.cpp
    src/connection_registry.cpp
    src/server.cpp
    src/json_commit_request_parser.cpp
    src/http_handler.cpp
    src/arena_allocator.cpp
    src/format.cpp
    ${CMAKE_BINARY_DIR}/json_tokens.cpp)

add_executable(weaseldb ${SOURCES})
add_dependencies(weaseldb generate_json_tokens)
target_link_libraries(
  weaseldb
  Threads::Threads
  toml11::toml11
  weaseljson
  simdutf::simdutf
  llhttp_static
  perfetto)

enable_testing()

# Create shared test data library
add_library(test_data STATIC benchmarks/test_data.cpp)
target_include_directories(test_data PUBLIC benchmarks)
target_link_libraries(test_data simdutf::simdutf)

add_executable(test_arena_allocator tests/test_arena_allocator.cpp
                                    src/arena_allocator.cpp src/format.cpp)
target_link_libraries(test_arena_allocator doctest::doctest)
target_include_directories(test_arena_allocator PRIVATE src)
target_compile_options(test_arena_allocator PRIVATE -UNDEBUG)

add_executable(
  test_commit_request
  tests/test_commit_request.cpp src/json_commit_request_parser.cpp
  tests/nlohmann_reference_parser.cpp tests/parser_comparison.cpp
  src/arena_allocator.cpp ${CMAKE_BINARY_DIR}/json_tokens.cpp)
add_dependencies(test_commit_request generate_json_tokens)
target_link_libraries(test_commit_request doctest::doctest weaseljson test_data
                      nlohmann_json::nlohmann_json simdutf::simdutf)
target_include_directories(test_commit_request PRIVATE src tests)
target_compile_options(test_commit_request PRIVATE -UNDEBUG)

add_executable(
  test_http_handler
  tests/test_http_handler.cpp src/http_handler.cpp src/arena_allocator.cpp
  src/connection.cpp src/connection_registry.cpp)
target_link_libraries(test_http_handler doctest::doctest llhttp_static
                      Threads::Threads perfetto)
target_include_directories(test_http_handler PRIVATE src)
target_compile_definitions(test_http_handler
                           PRIVATE DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
target_compile_options(test_http_handler PRIVATE -UNDEBUG)

add_executable(
  test_server_connection_return
  tests/test_server_connection_return.cpp
  src/server.cpp
  src/connection.cpp
  src/connection_registry.cpp
  src/arena_allocator.cpp
  src/config.cpp
  src/http_handler.cpp
  ${CMAKE_BINARY_DIR}/json_tokens.cpp)
add_dependencies(test_server_connection_return generate_json_tokens)
target_link_libraries(
  test_server_connection_return
  doctest::doctest
  llhttp_static
  Threads::Threads
  toml11::toml11
  perfetto
  weaseljson
  simdutf::simdutf)
target_include_directories(test_server_connection_return PRIVATE src)
target_compile_definitions(test_server_connection_return
                           PRIVATE DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
target_compile_options(test_server_connection_return PRIVATE -UNDEBUG)

# Metrics system test
add_executable(test_metric tests/test_metric.cpp src/metric.cpp
                           src/arena_allocator.cpp src/format.cpp)
target_link_libraries(test_metric doctest::doctest Threads::Threads
                      simdutf::simdutf weaseljson)
target_include_directories(test_metric PRIVATE src)
target_compile_options(test_metric PRIVATE -UNDEBUG)

# Register with CTest
add_test(NAME metric_tests COMMAND test_metric)

add_executable(bench_arena_allocator benchmarks/bench_arena_allocator.cpp
                                     src/arena_allocator.cpp)
target_link_libraries(bench_arena_allocator nanobench)
target_include_directories(bench_arena_allocator PRIVATE src)

add_executable(bench_volatile_loop benchmarks/bench_volatile_loop.cpp)
target_link_libraries(bench_volatile_loop nanobench)

add_executable(
  bench_commit_request
  benchmarks/bench_commit_request.cpp src/json_commit_request_parser.cpp
  src/arena_allocator.cpp ${CMAKE_BINARY_DIR}/json_tokens.cpp)
add_dependencies(bench_commit_request generate_json_tokens)
target_link_libraries(bench_commit_request nanobench weaseljson test_data
                      simdutf::simdutf)
target_include_directories(bench_commit_request PRIVATE src)

add_executable(
  bench_parser_comparison
  benchmarks/bench_parser_comparison.cpp src/json_commit_request_parser.cpp
  src/arena_allocator.cpp ${CMAKE_BINARY_DIR}/json_tokens.cpp)
add_dependencies(bench_parser_comparison generate_json_tokens)
target_link_libraries(bench_parser_comparison nanobench weaseljson test_data
                      nlohmann_json::nlohmann_json simdutf::simdutf)
target_include_directories(bench_parser_comparison
                           PRIVATE src ${rapidjson_SOURCE_DIR}/include)

add_executable(bench_thread_pipeline benchmarks/bench_thread_pipeline.cpp)
target_link_libraries(bench_thread_pipeline nanobench Threads::Threads)
target_include_directories(bench_thread_pipeline PRIVATE src)

add_executable(bench_format_comparison benchmarks/bench_format_comparison.cpp
                                       src/arena_allocator.cpp src/format.cpp)
target_link_libraries(bench_format_comparison nanobench)
target_include_directories(bench_format_comparison PRIVATE src)

# Metrics system benchmark
add_executable(bench_metric benchmarks/bench_metric.cpp src/metric.cpp
                            src/arena_allocator.cpp src/format.cpp)
target_link_libraries(bench_metric nanobench Threads::Threads simdutf::simdutf
                      weaseljson)
target_include_directories(bench_metric PRIVATE src)

# Register benchmark with CTest
add_test(NAME metric_benchmarks COMMAND bench_metric)

# Debug tools
add_executable(
  debug_arena tools/debug_arena.cpp src/json_commit_request_parser.cpp
              src/arena_allocator.cpp ${CMAKE_BINARY_DIR}/json_tokens.cpp)
add_dependencies(debug_arena generate_json_tokens)
target_link_libraries(debug_arena weaseljson simdutf::simdutf)
target_include_directories(debug_arena PRIVATE src)

# Load tester
add_executable(load_tester tools/load_tester.cpp)
target_link_libraries(load_tester Threads::Threads llhttp_static perfetto)

add_test(NAME arena_allocator_tests COMMAND test_arena_allocator)
add_test(NAME commit_request_tests COMMAND test_commit_request)
add_test(NAME http_handler_tests COMMAND test_http_handler)
add_test(NAME server_connection_return_tests
         COMMAND test_server_connection_return)
add_test(NAME arena_allocator_benchmarks COMMAND bench_arena_allocator)
add_test(NAME commit_request_benchmarks COMMAND bench_commit_request)
add_test(NAME parser_comparison_benchmarks COMMAND bench_parser_comparison)
add_test(NAME thread_pipeline_benchmarks COMMAND bench_thread_pipeline)
add_test(NAME format_comparison_benchmarks COMMAND bench_format_comparison)
