set(NINBOT_MODULE_SOURCES
    ninbot.c++
    internal.c++
    utils.c++
    geometry/geometry.c++
    geometry/algebras.c++
    geometry/SE.c++
    geometry/SO.c++
    units/units.c++
    pos/pos.c++
    pos/base.c++
    pos/R2.c++
    pos/R3.c++
    pos/pose.c++
    pos/mujoco.c++
)

# --- Library ---

add_library(ninbot)
add_library(ninbot::ninbot ALIAS ninbot)
target_compile_features(ninbot PUBLIC cxx_std_26)
set_target_properties(ninbot PROPERTIES
    CXX_STANDARD_REQUIRED ON
    INTERFACE_CXX_STANDARD_REQUIRED ON)
target_compile_options(ninbot PUBLIC $<$<CXX_COMPILER_ID:GNU>:-fmodules>)
target_sources(ninbot PUBLIC
    FILE_SET CXX_MODULES FILES ${NINBOT_MODULE_SOURCES}
)

target_include_directories(ninbot PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_LIBDIR}/ninbot/modules/src>
)

if(NINBOT_POS_DEFAULT_HOP_LIMIT)
    target_compile_definitions(ninbot PRIVATE
        POS_OFFSET_DEFAULT_HOP_LIMIT=${NINBOT_POS_DEFAULT_HOP_LIMIT})
endif()

# --- Install ---

install(TARGETS ninbot
    EXPORT ninbotTargets
    ARCHIVE       DESTINATION ${CMAKE_INSTALL_LIBDIR}
    FILE_SET CXX_MODULES DESTINATION ${CMAKE_INSTALL_LIBDIR}/ninbot/modules/src
)

install(FILES macros.hh
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/ninbot/modules/src
)

install(EXPORT ninbotTargets
    FILE      NinbotTargets.cmake
    NAMESPACE ninbot::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ninbot
)

export(EXPORT ninbotTargets
    FILE "${CMAKE_BINARY_DIR}/NinbotTargets.cmake"
    NAMESPACE ninbot::
)

configure_package_config_file(
    ${CMAKE_SOURCE_DIR}/cmake/NinbotConfig.cmake.in
    "${CMAKE_BINARY_DIR}/NinbotConfig.cmake"
    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ninbot
)

write_basic_package_version_file(
    "${CMAKE_BINARY_DIR}/NinbotConfigVersion.cmake"
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY SameMajorVersion
)

install(FILES
    "${CMAKE_BINARY_DIR}/NinbotConfig.cmake"
    "${CMAKE_BINARY_DIR}/NinbotConfigVersion.cmake"
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ninbot
)

# --- Syntax check ---

# syntax-check: compile all module sources (verifying syntax and semantics) without archiving.
# C++20 modules couple BMI generation with compilation, so -fsyntax-only cannot be used here —
# it would suppress BMI output and break the import chain for dependent modules.
add_library(ninbot-syntax OBJECT EXCLUDE_FROM_ALL)
target_sources(ninbot-syntax PUBLIC
    FILE_SET CXX_MODULES FILES ${NINBOT_MODULE_SOURCES}
)
target_include_directories(ninbot-syntax PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_features(ninbot-syntax PUBLIC cxx_std_26)
target_compile_options(ninbot-syntax PRIVATE -Wall -Wextra -Wconversion -Wshadow -Wpedantic -Werror
    $<$<CXX_COMPILER_ID:Clang>:-Wno-unused-command-line-argument>)

if(NOT CMAKE_BUILD_TYPE STREQUAL Release)
    add_custom_target(syntax DEPENDS ninbot-syntax)
endif()

# --- Tests ---

if(NINBOT_BUILD_TESTS)
    set(NINBOT_TEST_UNITS
        geometry/tests/algebra
        units/tests/units
        geometry/tests/R2
        geometry/tests/R3
        pos/tests/coordsys
    )

    foreach(test_path IN LISTS NINBOT_TEST_UNITS)
	cmake_path(GET test_path STEM stem)
	set(test_name "test-${stem}")
	add_executable(${test_name}
            test_framework.cc
            ${test_path}.test.c++
        )
        target_include_directories(${test_name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
        target_link_libraries(${test_name} PRIVATE ninbot)
        target_sources(${test_name} PUBLIC
            FILE_SET CXX_MODULES FILES approx_equal.c++
        )
	target_compile_options(${test_name} PRIVATE -Wall -Wextra -Wconversion -Wpedantic -Wshadow
		-fdiagnostics-color
		-Wno-unused-local-typedefs -Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable
		$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-command-line-argument>)
        add_test(NAME ${stem} COMMAND ${test_name})
    endforeach()

    # --- MuJoCo integration test ---

    if(NINBOT_BUILD_MUJOCO_TESTS)
        add_executable(test-mujoco
            pos/tests/mujoco.test.c++
            test_framework.cc
        )
        target_sources(test-mujoco PUBLIC
            FILE_SET CXX_MODULES FILES approx_equal.c++
        )
        target_include_directories(test-mujoco PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
        target_link_libraries(test-mujoco PRIVATE ninbot mujoco)
	target_compile_options(test-mujoco PRIVATE -Wall -Wextra -Wno-unused-local-typedefs
		-fdiagnostics-color
		-Wno-unused-parameter -Wno-unused-variable -Wno-unused-but-set-variable
		$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-command-line-argument>)
        configure_file(pos/tests/mujoco.test.xml mujoco.test.xml COPYONLY)
        add_test(NAME mujoco COMMAND test-mujoco)
        set_tests_properties(mujoco PROPERTIES
            WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
    endif()
endif()
