cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
project(fces-native
    VERSION 0.1.0
    DESCRIPTION "High-performance C++ FCES optimizer with libtorch integration"
    LANGUAGES CXX
)

# ============================================================================
# Build Configuration
# ============================================================================
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Options
option(FCES_BUILD_TESTS "Build unit tests" ON)
option(FCES_BUILD_BENCHMARKS "Build performance benchmarks" ON)
option(FCES_BUILD_EXAMPLES "Build examples" ON)
option(FCES_BUILD_PYTHON "Build Python extension" OFF)
option(FCES_ENABLE_OPENMP "Enable OpenMP for parallel evolution" ON)

# ============================================================================
# Dependencies
# ============================================================================

# libtorch (PyTorch C++ API)
find_package(Torch REQUIRED)
if(NOT MSVC)
    add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0)
endif()

# OpenMP (optional, for parallel population evaluation)
if(FCES_ENABLE_OPENMP)
    find_package(OpenMP)
    if(OpenMP_CXX_FOUND)
        message(STATUS "OpenMP found — parallel evolution enabled")
    else()
        message(STATUS "OpenMP not found — falling back to serial execution")
    endif()
endif()

# ============================================================================
# FCES Core Library
# ============================================================================
add_library(fces STATIC
    src/config.cpp
    src/controller.cpp
    src/population.cpp
    src/fitness.cpp
    src/evolution.cpp
    src/spectral.cpp
    src/oscillation.cpp
    src/optimizer.cpp
    src/telemetry.cpp
)

target_include_directories(fces
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
)

target_link_libraries(fces PUBLIC ${TORCH_LIBRARIES})

if(OpenMP_CXX_FOUND)
    target_link_libraries(fces PUBLIC OpenMP::OpenMP_CXX)
    target_compile_definitions(fces PUBLIC FCES_USE_OPENMP)
endif()

# MSVC-specific flags
if(MSVC)
    target_compile_options(fces PRIVATE /W4 /permissive-)
else()
    target_compile_options(fces PRIVATE -Wall -Wextra -Wpedantic -O2)
endif()

# ============================================================================
# Tests (Google Test)
# ============================================================================
if(FCES_BUILD_TESTS)
    enable_testing()

    include(FetchContent)
    FetchContent_Declare(
        googletest
        URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip
    )
    # For Windows: Prevent overriding the parent project's compiler/linker settings
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
    FetchContent_MakeAvailable(googletest)

    add_executable(fces_tests
        tests/test_controller.cpp
        tests/test_population.cpp
        tests/test_optimizer.cpp
        tests/test_fitness.cpp
    )

    target_link_libraries(fces_tests PRIVATE fces GTest::gtest_main)

    include(GoogleTest)
    gtest_discover_tests(fces_tests)
endif()

# ============================================================================
# Benchmarks (Google Benchmark)
# ============================================================================
if(FCES_BUILD_BENCHMARKS)
    include(FetchContent)
    FetchContent_Declare(
        benchmark
        URL https://github.com/google/benchmark/archive/refs/tags/v1.8.3.zip
    )
    set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
    FetchContent_MakeAvailable(benchmark)

    add_executable(fces_bench
        benchmarks/bench_evolve.cpp
        benchmarks/bench_step.cpp
    )

    target_link_libraries(fces_bench PRIVATE fces benchmark::benchmark_main)
endif()

# ============================================================================
# Examples
# ============================================================================
if(FCES_BUILD_EXAMPLES)
    add_executable(simple_optimization examples/simple_optimization.cpp)
    target_link_libraries(simple_optimization PRIVATE fces)

    add_executable(pytorch_integration examples/pytorch_integration.cpp)
    target_link_libraries(pytorch_integration PRIVATE fces)

    add_executable(telemetry_and_inference examples/telemetry_and_inference.cpp)
    target_link_libraries(telemetry_and_inference PRIVATE fces)
endif()

# ============================================================================
# Python Extension (pybind11)
# ============================================================================
if(FCES_BUILD_PYTHON)
    find_package(pybind11 REQUIRED)
    pybind11_add_module(fces_native python/fces_native.cpp)
    target_link_libraries(fces_native PRIVATE fces)
endif()

# ============================================================================
# Install
# ============================================================================
install(TARGETS fces
    EXPORT fcesTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    INCLUDES DESTINATION include
)

install(DIRECTORY include/fces DESTINATION include)

message(STATUS "")
message(STATUS "=== FCES Native Build Configuration ===")
message(STATUS "  Version:     ${PROJECT_VERSION}")
message(STATUS "  C++ Standard: ${CMAKE_CXX_STANDARD}")
message(STATUS "  Tests:       ${FCES_BUILD_TESTS}")
message(STATUS "  Benchmarks:  ${FCES_BUILD_BENCHMARKS}")
message(STATUS "  Examples:    ${FCES_BUILD_EXAMPLES}")
message(STATUS "  Python:      ${FCES_BUILD_PYTHON}")
message(STATUS "  OpenMP:      ${OpenMP_CXX_FOUND}")
message(STATUS "  Torch:       ${Torch_VERSION}")
message(STATUS "========================================")
message(STATUS "")
