cmake_minimum_required(VERSION 3.16)
project(unitree_legged_sdk VERSION 3.8.6 LANGUAGES CXX)

if(POLICY CMP0167)
  cmake_policy(SET CMP0167 NEW)
endif()

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
find_package(Threads REQUIRED)
find_package(Boost REQUIRED)

option(GO1_PRO_BUILD_EXAMPLES "Build portable official-API C++ examples" ON)
option(GO1_PRO_BUILD_TESTS "Build C++ compatibility tests" ON)

add_library(unitree_legged_sdk
  src/loop.cpp
  src/pro_codec.cpp
  src/quadruped.cpp
  src/safety.cpp
  src/udp.cpp
)
add_library(unitree_legged_sdk::unitree_legged_sdk ALIAS unitree_legged_sdk)
target_compile_features(unitree_legged_sdk PUBLIC cxx_std_14)
target_include_directories(unitree_legged_sdk
  PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
  PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_compile_definitions(unitree_legged_sdk PRIVATE
  GO1_PRO_SOURCE_STATE_FILE="${CMAKE_CURRENT_SOURCE_DIR}/go1_pro_sdk/_data/blowfish_state.bin"
  GO1_PRO_INSTALL_STATE_FILE="${CMAKE_INSTALL_FULL_DATADIR}/go1_pro_sdk/blowfish_state.bin"
)
if(TARGET Boost::headers)
  set(GO1_PRO_BOOST_TARGET Boost::headers)
else()
  set(GO1_PRO_BOOST_TARGET Boost::boost)
endif()
target_link_libraries(unitree_legged_sdk PUBLIC Threads::Threads ${GO1_PRO_BOOST_TARGET})

if(GO1_PRO_BUILD_EXAMPLES)
  add_executable(example_official_compatible_position
    examples/cpp/example_official_compatible_position.cpp)
  target_link_libraries(example_official_compatible_position PRIVATE unitree_legged_sdk)
endif()

if(GO1_PRO_BUILD_TESTS)
  enable_testing()
  add_executable(test_cpp_compat tests/cpp/test_compat.cpp)
  target_include_directories(test_cpp_compat PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
  set(GO1_PRO_CAPTURE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/data/captures" CACHE PATH
      "Optional private real-robot capture fixture directory")
  if(EXISTS "${GO1_PRO_CAPTURE_DIR}/mcu_response_new.bin"
      AND EXISTS "${GO1_PRO_CAPTURE_DIR}/mcu_response.bin"
      AND EXISTS "${GO1_PRO_CAPTURE_DIR}/real_lowcmd.bin"
      AND EXISTS "${GO1_PRO_CAPTURE_DIR}/real_lowcmd_decrypted.bin")
    target_compile_definitions(test_cpp_compat PRIVATE
      GO1_PRO_HAVE_CAPTURE_FIXTURES=1
      GO1_PRO_TEST_CAPTURE="${GO1_PRO_CAPTURE_DIR}/mcu_response_new.bin"
      GO1_PRO_TEST_CAPTURE_OLD="${GO1_PRO_CAPTURE_DIR}/mcu_response.bin"
      GO1_PRO_TEST_LOWCMD="${GO1_PRO_CAPTURE_DIR}/real_lowcmd.bin"
      GO1_PRO_TEST_LOWCMD_PLAIN="${GO1_PRO_CAPTURE_DIR}/real_lowcmd_decrypted.bin")
  else()
    message(STATUS "Private data/captures fixtures not found; C++ capture checks disabled")
  endif()
  target_link_libraries(test_cpp_compat PRIVATE unitree_legged_sdk)
  add_test(NAME cpp_official_compat COMMAND test_cpp_compat)

  set(GO1_PRO_TEST_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/test-install")
  set(GO1_PRO_TEST_CONSUMER_BUILD "${CMAKE_CURRENT_BINARY_DIR}/package-consumer")
  add_test(NAME cpp_package_install
    COMMAND ${CMAKE_COMMAND} --install ${CMAKE_CURRENT_BINARY_DIR}
            --prefix ${GO1_PRO_TEST_INSTALL_DIR})
  add_test(NAME cpp_package_configure
    COMMAND ${CMAKE_COMMAND}
            -S ${CMAKE_CURRENT_SOURCE_DIR}/tests/cpp/package_consumer
            -B ${GO1_PRO_TEST_CONSUMER_BUILD}
            -DCMAKE_PREFIX_PATH=${GO1_PRO_TEST_INSTALL_DIR}
            "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
            "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS}")
  set_tests_properties(cpp_package_configure PROPERTIES DEPENDS cpp_package_install)
  add_test(NAME cpp_package_build
    COMMAND ${CMAKE_COMMAND} --build ${GO1_PRO_TEST_CONSUMER_BUILD})
  set_tests_properties(cpp_package_build PROPERTIES DEPENDS cpp_package_configure)
  add_test(NAME cpp_package_run
    COMMAND ${GO1_PRO_TEST_CONSUMER_BUILD}/package_consumer)
  set_tests_properties(cpp_package_run PROPERTIES DEPENDS cpp_package_build)
endif()

install(TARGETS unitree_legged_sdk EXPORT unitree_legged_sdkTargets
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
  INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(DIRECTORY include/unitree_legged_sdk DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES go1_pro_sdk/_data/blowfish_state.bin DESTINATION ${CMAKE_INSTALL_DATADIR}/go1_pro_sdk)
install(EXPORT unitree_legged_sdkTargets
  FILE unitree_legged_sdkTargets.cmake
  NAMESPACE unitree_legged_sdk::
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/unitree_legged_sdk)

configure_package_config_file(
  cmake/unitree_legged_sdkConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/unitree_legged_sdkConfig.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/unitree_legged_sdk)
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/unitree_legged_sdkConfigVersion.cmake
  VERSION ${PROJECT_VERSION}
  COMPATIBILITY SameMajorVersion)
install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/unitree_legged_sdkConfig.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/unitree_legged_sdkConfigVersion.cmake
  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/unitree_legged_sdk)
