cmake_minimum_required(VERSION 3.16)
project(rw VERSION 1.0 LANGUAGES CXX)

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

# === Source directory ===
set(RW_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)

# === Compiler settings ===
# Common warning flags (both compilers)
add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-shadow -Wno-error
    # Suppressed: common legacy patterns
    -Wno-deprecated-declarations   # 134x: std::iterator deprecation
    -Wno-ignored-qualifiers        # 100x: const on by-value return
    -Wno-extern-initializer        # 86x: extern with initializer
    -Wno-unknown-pragmas           # 49x
    -Wno-missing-braces            # 21x
    -Wno-missing-field-initializers # 24x
    -Wno-sign-compare              # 225x: size_t vs int comparisons
    -Wno-unused-function           # 8x: false positives in template/overload ctx
    -Wno-unused-const-variable     # 10x: debug/legacy constants
)
add_compile_definitions(RW_DLL)

# Legacy code uses bare strcat/strcpy/etc without <cstring> include
# std_c_compat.hpp brings these into global namespace via using-declarations
# Required for GCC 13+, Clang 18+ (strict two-phase name lookup)
add_compile_options(-include "${RW_SRC}/util/std_c_compat.hpp")

# === System dependencies ===
find_package(ZLIB REQUIRED)

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options(-fdelayed-template-parsing)
    # Clang-specific suppressions
    add_compile_options(
        -Wno-writable-strings          # 4549x: string literal → char* (C API convention)
        -Wno-non-c-typedef-for-linkage # 211x: C-compat typedef struct
        -Wno-deprecated-copy-with-user-provided-copy # 54x
        -Wno-unused-private-field      # 8x
        -Wno-cast-function-type-mismatch # 7x
        -Wno-vexing-parse              # 2x
        -Wno-reorder-ctor              # 69x: member init order
        -Wno-logical-op-parentheses    # 22x: remaining after header fixes
    )
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    # GCC 13+ strict two-phase name lookup; legacy codebase needs fpermissive
    add_compile_options(-fpermissive)
    # GCC-specific suppressions (equivalents to Clang flags above)
    add_compile_options(
        -Wno-reorder                   # GCC equivalent of -Wno-reorder-ctor
        -Wno-parentheses               # GCC equivalent of -Wno-logical-op-parentheses
    )
endif()

# === Source file list (externalized to reduce CMakeLists.txt token footprint) ===
include(sources.cmake)

# === Core library ===
add_library(rw_core STATIC ${RW_CORE_SOURCES})
target_link_libraries(rw_core PUBLIC ZLIB::ZLIB)
target_include_directories(rw_core PUBLIC
    ${RW_SRC}
    ${RW_SRC}/aktsource
    ${RW_SRC}/core
    ${RW_SRC}/datatypes
    ${RW_SRC}/db
    ${RW_SRC}/domain
    ${RW_SRC}/goae
    ${RW_SRC}/interface
    ${RW_SRC}/le
    ${RW_SRC}/methods
    ${RW_SRC}/rest
    ${RW_SRC}/rw_actions
    ${RW_SRC}/rw_predicates
    ${RW_SRC}/sb_meth
    ${RW_SRC}/statistik
    ${RW_SRC}/taetigkeitort
    ${RW_SRC}/ur_meth
    ${RW_SRC}/util
    ${RW_SRC}/xml
    ${RW_SRC}/json
)

# === HostRW executable ===
option(BUILD_HOSTRW "Build the HostRW executable (requires Oracle/Sybase)" OFF)

if(BUILD_HOSTRW)
    add_executable(rw_host
        ${RW_SRC}/core/rw.cpp
        ${RW_SRC}/rest/rw_host.cpp
        ${RW_SRC}/core/regelmaschine.cpp
        ${RW_SRC}/util/hp_rw.cpp
        ${RW_SRC}/rest/wop.cpp
        ${RW_SRC}/rest/wop_win.cpp
        ${RW_SRC}/core/initrw.cpp
        ${RW_SRC}/core/rw_dll.cpp
        ${RW_SRC}/db/msdbconnection.cpp
        ${RW_SRC}/db/msdb_dbms.cpp
        ${RW_SRC}/db/msdb_dummy.cpp
        ${RW_SRC}/util/msgetopt.cpp
        ${RW_SRC}/rest/PraxisVerbundLock.cpp
    )
    target_compile_definitions(rw_host PRIVATE KVAI_HOSTRW RW_DLL)
    target_link_libraries(rw_host PRIVATE rw_core)
endif()

# === Test executable ===
option(BUILD_TESTS "Build test executables" OFF)

if(BUILD_TESTS)
    enable_testing()

    # Catch2 include path for new-style tests
    set(CATCH2_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests/catch2)

    function(add_rw_test name)
        add_executable(${name} tests/${name}.cpp)
        target_link_libraries(${name} PRIVATE rw_core)
        add_test(NAME ${name} COMMAND ${name})
    endfunction()

    add_rw_test(xml_test)
    add_rw_test(json_test)
    add_rw_test(json_converter_test)
    add_rw_test(json_deserialize_test)
    add_rw_test(datecalc_test)
    add_rw_test(tools_test)
    add_rw_test(menge_test)
    add_rw_test(bitset_test)
    add_rw_test(map_test)
    add_rw_test(leer_test)
    add_rw_test(list_test)
    add_rw_test(mstimer_test)
    add_rw_test(msmem_test)
    add_rw_test(intmenge_test)
    add_rw_test(infrastructure_test)
    add_rw_test(jsontools_test)
    add_rw_test(zlibcompress_test)

    # Catch2-based tests
    add_executable(bitset_catch_test tests/bitset_catch_test.cpp)
    target_include_directories(bitset_catch_test PRIVATE ${CATCH2_INCLUDE_DIR})
    target_link_libraries(bitset_catch_test PRIVATE rw_core)
    add_test(NAME bitset_catch_test COMMAND bitset_catch_test)

    add_executable(leistungflags_test tests/leistungflags_test.cpp)
    target_include_directories(leistungflags_test PRIVATE ${CATCH2_INCLUDE_DIR})
    target_link_libraries(leistungflags_test PRIVATE rw_core)
    add_test(NAME leistungflags_test COMMAND leistungflags_test)

    add_executable(predicates_test tests/predicates_test.cpp)
    target_include_directories(predicates_test PRIVATE ${CATCH2_INCLUDE_DIR} tests)
    target_link_libraries(predicates_test PRIVATE rw_core)
    add_test(NAME predicates_test COMMAND predicates_test)

    add_executable(actions_test tests/actions_test.cpp)
    target_include_directories(actions_test PRIVATE ${CATCH2_INCLUDE_DIR} tests)
    target_link_libraries(actions_test PRIVATE rw_core)
    add_test(NAME actions_test COMMAND actions_test)

    # Phase 3 — Integrationstest (mit initRegelwerk())
    add_executable(predicates_batch1_test tests/predicates_batch1_test.cpp)
    target_include_directories(predicates_batch1_test PRIVATE ${CATCH2_INCLUDE_DIR} tests)
    target_link_libraries(predicates_batch1_test PRIVATE rw_core)
    add_test(NAME predicates_batch1_test COMMAND predicates_batch1_test)

    add_executable(integration_test tests/integration_test.cpp src/core/initrw.cpp
        src/db/msdbconnection.cpp src/db/msdb_dummy.cpp
        src/util/msgetopt.cpp
        tests/xml_vq_data_stub.cpp
    )
    target_include_directories(integration_test PRIVATE ${CATCH2_INCLUDE_DIR})
    target_link_libraries(integration_test PRIVATE rw_core)
    add_test(NAME integration_test COMMAND integration_test)
endif()