cmake_minimum_required(VERSION 3.16)
project(NowYouSeeMe VERSION 1.0.0 LANGUAGES CXX)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Build type
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

# Output directories
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# Options
option(BUILD_TESTS "Build tests" OFF)
option(BUILD_EXAMPLES "Build examples" ON)
option(USE_CUDA "Enable CUDA support" ON)
option(USE_OPENCV "Enable OpenCV support" ON)

# Find required packages
find_package(OpenCV REQUIRED)
find_package(Eigen3 REQUIRED)
find_package(PkgConfig REQUIRED)

# Find optional packages
find_package(CUDA QUIET)
if(CUDA_FOUND AND USE_CUDA)
    enable_language(CUDA)
    set(CMAKE_CUDA_STANDARD 17)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
    message(STATUS "CUDA support enabled")
else()
    message(STATUS "CUDA support disabled")
endif()

# Find additional libraries
pkg_check_modules(FFTW3 REQUIRED fftw3)
pkg_check_modules(SPDLOG REQUIRED spdlog)
pkg_check_modules(CURL REQUIRED libcurl)
pkg_check_modules(JSONCPP REQUIRED jsoncpp)

# Include directories
include_directories(
    ${CMAKE_SOURCE_DIR}/src
    ${CMAKE_SOURCE_DIR}/include
    ${OpenCV_INCLUDE_DIRS}
    ${EIGEN3_INCLUDE_DIR}
    ${FFTW3_INCLUDE_DIRS}
    ${SPDLOG_INCLUDE_DIRS}
    ${CURL_INCLUDE_DIRS}
    ${JSONCPP_INCLUDE_DIRS}
)

# Link directories
link_directories(
    ${FFTW3_LIBRARY_DIRS}
    ${SPDLOG_LIBRARY_DIRS}
    ${CURL_LIBRARY_DIRS}
    ${JSONCPP_LIBRARY_DIRS}
)

# Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0")
else()
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DNDEBUG")
endif()

# Create library targets
add_library(nowyouseeme_core SHARED
    src/ingestion/sync_service.cpp
    src/calibration/calibrate_camera.cpp
    src/rf_slam/aoa_estimator.cpp
    src/rf_slam/rf_slam.cpp
    src/vision_slam/orb_interface.cpp
    src/fusion/ekf_fusion.cpp
    src/fusion/particle_filter.cpp
    src/reconstruction/mesh_optimize.cpp
    src/nerf/render_nerf.cpp
    src/api/device_manager.cpp
    src/cloud/azure_integration.cpp
)

# Set library properties
set_target_properties(nowyouseeme_core PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION ${PROJECT_VERSION_MAJOR}
    PUBLIC_HEADER ""
)

# Link libraries
target_link_libraries(nowyouseeme_core
    ${OpenCV_LIBS}
    ${EIGEN3_LIBRARIES}
    ${FFTW3_LIBRARIES}
    ${SPDLOG_LIBRARIES}
    ${CURL_LIBRARIES}
    ${JSONCPP_LIBRARIES}
    pthread
)

if(CUDA_FOUND AND USE_CUDA)
    target_link_libraries(nowyouseeme_core ${CUDA_LIBRARIES})
    target_compile_definitions(nowyouseeme_core PRIVATE USE_CUDA)
endif()

# Create executable targets
add_executable(sync_service src/ingestion/sync_service.cpp)
target_link_libraries(sync_service nowyouseeme_core)

add_executable(camera_calibration src/calibration/calibrate_camera.cpp)
target_link_libraries(camera_calibration nowyouseeme_core)

add_executable(aoa_estimator src/rf_slam/aoa_estimator.cpp)
target_link_libraries(aoa_estimator nowyouseeme_core)

add_executable(rf_slam src/rf_slam/rf_slam.cpp)
target_link_libraries(rf_slam nowyouseeme_core)

add_executable(orb_slam src/vision_slam/orb_interface.cpp)
target_link_libraries(orb_slam nowyouseeme_core)

add_executable(ekf_fusion src/fusion/ekf_fusion.cpp)
target_link_libraries(ekf_fusion nowyouseeme_core)

add_executable(particle_filter src/fusion/particle_filter.cpp)
target_link_libraries(particle_filter nowyouseeme_core)

add_executable(mesh_optimize src/reconstruction/mesh_optimize.cpp)
target_link_libraries(mesh_optimize nowyouseeme_core)

add_executable(render_nerf src/nerf/render_nerf.cpp)
target_link_libraries(render_nerf nowyouseeme_core)

add_executable(device_manager src/api/device_manager.cpp)
target_link_libraries(device_manager nowyouseeme_core)

add_executable(azure_integration src/cloud/azure_integration.cpp)
target_link_libraries(azure_integration nowyouseeme_core)

# Tests
if(BUILD_TESTS)
    enable_testing()
    find_package(GTest REQUIRED)
    
    # Add test executable
    add_executable(run_tests
        tests/test_sync_service.cpp
        tests/test_calibration.cpp
        tests/test_rf_slam.cpp
        tests/test_vision_slam.cpp
        tests/test_fusion.cpp
    )
    
    target_link_libraries(run_tests
        nowyouseeme_core
        GTest::GTest
        GTest::Main
    )
    
    # Add tests
    add_test(NAME SyncServiceTest COMMAND run_tests --gtest_filter=SyncServiceTest.*)
    add_test(NAME CalibrationTest COMMAND run_tests --gtest_filter=CalibrationTest.*)
    add_test(NAME RFSLAMTest COMMAND run_tests --gtest_filter=RFSLAMTest.*)
    add_test(NAME VisionSLAMTest COMMAND run_tests --gtest_filter=VisionSLAMTest.*)
    add_test(NAME FusionTest COMMAND run_tests --gtest_filter=FusionTest.*)
endif()

# Examples
if(BUILD_EXAMPLES)
    add_executable(example_camera_capture examples/camera_capture.cpp)
    target_link_libraries(example_camera_capture nowyouseeme_core)
    
    add_executable(example_csi_capture examples/csi_capture.cpp)
    target_link_libraries(example_csi_capture nowyouseeme_core)
    
    add_executable(example_calibration examples/calibration_example.cpp)
    target_link_libraries(example_calibration nowyouseeme_core)
endif()

# Installation
install(TARGETS nowyouseeme_core
    EXPORT NowYouSeeMeTargets
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
    RUNTIME DESTINATION bin
    PUBLIC_HEADER DESTINATION include
)

install(TARGETS
    sync_service
    camera_calibration
    aoa_estimator
    rf_slam
    orb_slam
    ekf_fusion
    particle_filter
    mesh_optimize
    render_nerf
    device_manager
    azure_integration
    DESTINATION bin
)

# Install headers
install(DIRECTORY include/ DESTINATION include)

# Export targets
install(EXPORT NowYouSeeMeTargets
    FILE NowYouSeeMeTargets.cmake
    NAMESPACE NowYouSeeMe::
    DESTINATION lib/cmake/NowYouSeeMe
)

# Create config file
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    NowYouSeeMeConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)

configure_file(
    cmake/NowYouSeeMeConfig.cmake.in
    NowYouSeeMeConfig.cmake
    @ONLY
)

install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/NowYouSeeMeConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/NowYouSeeMeConfigVersion.cmake
    DESTINATION lib/cmake/NowYouSeeMe
)

# Print configuration summary
message(STATUS "")
message(STATUS "NowYouSeeMe Configuration Summary:")
message(STATUS "  Build type: ${CMAKE_BUILD_TYPE}")
message(STATUS "  C++ standard: ${CMAKE_CXX_STANDARD}")
message(STATUS "  CUDA support: ${CUDA_FOUND}")
message(STATUS "  OpenCV version: ${OpenCV_VERSION}")
message(STATUS "  Eigen3 version: ${EIGEN3_VERSION}")
message(STATUS "  Build tests: ${BUILD_TESTS}")
message(STATUS "  Build examples: ${BUILD_EXAMPLES}")
message(STATUS "") 