cmake_minimum_required(VERSION 3.14...3.27)

# 设置 CMake 策略（移除非必要的新策略）
cmake_policy(SET CMP0074 NEW)  # 保留必要的包根目录策略

# 包含 FetchContent 模块
include(FetchContent)

# 生成 compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(collision_avoidance)

# 静态链接选项：
# - 优先静态链接 Boost（以及可选的 libcurl，取决于系统是否提供静态库）
# - 同时静态链接 libstdc++/libgcc，减少目标机运行时依赖
option(LINK_STATIC_DEPS "Prefer static linking for third-party deps when available" OFF)
option(FULL_STATIC "Link fully static binary (-static). Requires static libs (glibc-static, libcurl.a, etc.)" OFF)

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

# 检查编译器版本
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
        message(FATAL_ERROR "GCC 版本需要 >= 7.0 以支持 C++17")
    endif()
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
    if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
        message(FATAL_ERROR "Clang 版本需要 >= 5.0 以支持 C++17")
    endif()
endif()

# 设置输出目录
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# 设置 Boost
set(Boost_NO_WARN_NEW_VERSIONS 1)
set(Boost_USE_STATIC_LIBS OFF)
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)

if(LINK_STATIC_DEPS)
    set(Boost_USE_STATIC_LIBS ON)
    # libcurl 静态库在 CentOS 7 上可能需要额外的 -devel/-static 包支持；若不存在，FindCURL 仍会回退到动态库
    set(CURL_USE_STATIC_LIBS ON)
endif()
if(NOT APPLE)
    # 允许外部通过 -DBOOST_ROOT/-DBOOST_LIBRARYDIR 覆盖（例如容器内自编译 Boost 到 /opt/boost-1.69）
    if(NOT DEFINED BOOST_ROOT)
        # 旧环境默认（若存在 boost169 包）
        set(BOOST_ROOT "/usr/include/boost169")
    endif()
    if(NOT DEFINED BOOST_LIBRARYDIR)
        set(BOOST_LIBRARYDIR "/usr/lib64/boost169")
    endif()
else()
    # 在 macOS 上使用 Homebrew 安装的 Boost（同样允许外部覆盖）
    if(NOT DEFINED BOOST_ROOT)
        set(BOOST_ROOT "/opt/homebrew/Cellar/boost/1.87.0")
    endif()
    if(NOT DEFINED BOOST_LIBRARYDIR)
        set(BOOST_LIBRARYDIR "/opt/homebrew/Cellar/boost/1.87.0/lib")
    endif()
endif()

# 设置 CMake 策略（在 find_package(Boost) 前添加）
if(POLICY CMP0167)
    cmake_policy(SET CMP0167 OLD)  # 强制使用传统 FindBoost 模块
endif()

find_package(Boost 1.69.0 REQUIRED COMPONENTS 
    system 
    filesystem 
    thread 
    chrono 
    date_time 
    atomic
    regex  # 添加缺失的 regex 组件
)

# 添加 libcurl
find_package(CURL REQUIRED)

# JSON 库：优先使用系统包；若离线环境无法 FetchContent，则允许用户提供本地源码路径
# 用法：
#   -DLOCAL_NLOHMANN_JSON_SOURCE_DIR=/path/to/json (包含 CMakeLists.txt)
# 或安装系统包提供 nlohmann_json::nlohmann_json
set(LOCAL_NLOHMANN_JSON_SOURCE_DIR "" CACHE PATH "Local nlohmann/json source dir (offline fallback). Should contain CMakeLists.txt")

# 若仓库内已带 json 子目录，则默认优先使用它（避免 FetchContent 联网/卡住）
if(NOT LOCAL_NLOHMANN_JSON_SOURCE_DIR AND EXISTS "${CMAKE_SOURCE_DIR}/json/CMakeLists.txt")
    set(LOCAL_NLOHMANN_JSON_SOURCE_DIR "${CMAKE_SOURCE_DIR}/json")
endif()

find_package(nlohmann_json QUIET)

if(NOT TARGET nlohmann_json::nlohmann_json)
    if(LOCAL_NLOHMANN_JSON_SOURCE_DIR)
        if(EXISTS "${LOCAL_NLOHMANN_JSON_SOURCE_DIR}/CMakeLists.txt")
            message(STATUS "Using local nlohmann/json from: ${LOCAL_NLOHMANN_JSON_SOURCE_DIR}")
            add_subdirectory("${LOCAL_NLOHMANN_JSON_SOURCE_DIR}" "${CMAKE_BINARY_DIR}/_deps/nlohmann_json-local")
        else()
            message(FATAL_ERROR "LOCAL_NLOHMANN_JSON_SOURCE_DIR is set but CMakeLists.txt not found under: ${LOCAL_NLOHMANN_JSON_SOURCE_DIR}")
        endif()
    else()
        FetchContent_Declare(
            nlohmann_json
            GIT_REPOSITORY https://github.com/nlohmann/json.git
            GIT_TAG v3.11.3
            GIT_SHALLOW TRUE
        )
        FetchContent_MakeAvailable(nlohmann_json)
    endif()
endif()

if(NOT TARGET nlohmann_json::nlohmann_json)
    message(FATAL_ERROR "nlohmann_json::nlohmann_json not available. Install a system package providing it or set -DLOCAL_NLOHMANN_JSON_SOURCE_DIR=<path-to-nlohmann-json-source>.")
endif()

# 源文件列表
set(LIB_SOURCES
    src/collector/DataCollector.cpp
    src/collector/DataSourceConfig.cpp
    src/core/System.cpp
    src/detector/CollisionDetector.cpp
    src/detector/SafetyZone.cpp
    src/network/HTTPDataSource.cpp
    src/network/WebSocketServer.cpp
    src/network/HTTPClient.cpp
    src/network/TrafficLightHttpServer.cpp
    src/network/TrafficLightTcpServer.cpp
    src/network/ConfigHttpServer.cpp
    src/spatial/CoordinateConverter.cpp
    src/types/BasicTypes.cpp
    src/types/VehicleData.cpp
    src/vehicle/ControllableVehicles.cpp
    src/config/AirportBounds.cpp
    src/config/SystemConfig.cpp
    src/config/IntersectionConfig.cpp
    src/detector/TrafficLightDetector.cpp
)

# 创建主库
add_library(${PROJECT_NAME}_lib ${LIB_SOURCES})

target_include_directories(${PROJECT_NAME}_lib
    PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/src
    ${Boost_INCLUDE_DIRS}
    ${CURL_INCLUDE_DIRS}
)

target_link_libraries(${PROJECT_NAME}_lib
    PUBLIC
    Boost::system
    Boost::filesystem
    Boost::thread
    Boost::chrono
    Boost::date_time
    Boost::atomic
    Boost::regex
    nlohmann_json::nlohmann_json
    Threads::Threads
    -pthread
)

# CURL 链接：全静态时优先使用 CURL_LIBRARY/CURL_LIBRARIES（避免使用可能指向错误路径的导入目标）
if(FULL_STATIC)
    if(CURL_INCLUDE_DIR)
        target_include_directories(${PROJECT_NAME}_lib PUBLIC ${CURL_INCLUDE_DIR})
    endif()
    if(CURL_LIBRARY)
        target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARY})
    else()
        target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARIES})
    endif()
else()
    if(TARGET CURL::libcurl)
        target_link_libraries(${PROJECT_NAME}_lib PUBLIC CURL::libcurl)
    else()
        target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${CURL_LIBRARIES})
    endif()
endif()

if(LINK_STATIC_DEPS)
    # FindCURL 在静态场景下通常不会把 libcurl 的传递依赖带出来；这里补充常见依赖。
    # 若链接仍报缺库，可用你自编的 curl: `curl-config --static-libs` 得到完整列表再补齐。
    target_link_libraries(${PROJECT_NAME}_lib PUBLIC dl z ssl crypto rt resolv)
endif()

# 创建主可执行文件
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE ${PROJECT_NAME}_lib)

if(LINK_STATIC_DEPS)
    target_link_options(${PROJECT_NAME} PRIVATE -static-libstdc++ -static-libgcc)
endif()

if(FULL_STATIC)
    target_link_options(${PROJECT_NAME} PRIVATE -static)
endif()

# 添加一个选项来控制是否编译测试
if(APPLE)
    option(BUILD_TESTS "Build test cases" ON)
else()
    option(BUILD_TESTS "Build test cases" OFF)
endif()

# 添加测试
if(BUILD_TESTS AND EXISTS "${CMAKE_SOURCE_DIR}/tests")
    if(APPLE)
        # macOS 使用 FetchContent 下载 googletest
        FetchContent_Declare(
            googletest
            GIT_REPOSITORY https://github.com/google/googletest.git
            GIT_TAG v1.15.2
        )
        FetchContent_MakeAvailable(googletest)
    else()
        # CentOS 也使用 FetchContent 下载 googletest
        FetchContent_Declare(
            googletest
            GIT_REPOSITORY https://github.com/google/googletest.git
            GIT_TAG v1.15.2
        )
        FetchContent_MakeAvailable(googletest)
    endif()

    # 添加 tests 子目录
    add_subdirectory(tests)
endif()

# 打印配置信息
message(STATUS "CMAKE_SOURCE_DIR: ${CMAKE_SOURCE_DIR}")
message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message(STATUS "Boost_INCLUDE_DIRS: ${Boost_INCLUDE_DIRS}")
message(STATUS "Boost_LIBRARIES: ${Boost_LIBRARIES}")
message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
message(STATUS "CMAKE_EXE_LINKER_FLAGS: ${CMAKE_EXE_LINKER_FLAGS}")

# 复制配置文件到构建目录
configure_file(${CMAKE_SOURCE_DIR}/config/system_config.json ${CMAKE_BINARY_DIR}/config/system_config.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/intersections.json ${CMAKE_BINARY_DIR}/config/intersections.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/airport_bounds.json ${CMAKE_BINARY_DIR}/config/airport_bounds.json COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/config/unmanned_vehicles.json ${CMAKE_BINARY_DIR}/config/unmanned_vehicles.json COPYONLY)

# 查找 Threads 包
find_package(Threads REQUIRED)

if(NOT APPLE)
    target_link_libraries(collision_avoidance
        PRIVATE
        ${PROJECT_NAME}_lib
    )
endif()