cmake_minimum_required(VERSION 3.20)

set(PROJECT_NAME "conformallab_core")
project(${PROJECT_NAME} LANGUAGES C CXX)

message(STATUS "Configuring ${PROJECT_NAME}...")

# ── Build modes ────────────────────────────────────────────────────────────────
#
#   Default (CI fast / pure-math tests):
#     cmake -S code -B build
#     Only Eigen + GTest required.  36 non-CGAL tests.
#
#   -DWITH_CGAL_TESTS=ON   CGAL test suite only — no viewer, no CLI app.
#     cmake -S code -B build -DWITH_CGAL_TESTS=ON
#     Requires: system Boost headers (apt install libboost-dev).
#     Builds:   conformallab_cgal_tests  (158 tests).
#     Does NOT require wayland-scanner, GLFW, libigl or a display.
#     Use this in headless CI.
#
#   -DWITH_CGAL=ON         Full build: CLI app + viewer + examples + CGAL tests.
#     cmake -S code -B build -DWITH_CGAL=ON
#     Requires: Boost + Wayland/X11 dev headers (wayland-scanner, libx11-dev …).
#     Automatically enables WITH_VIEWER.
#     Use this for local development with the interactive viewer.
#
#   -DWITH_VIEWER=ON        Viewer library only (libigl / GLFW / GLAD).
#
# ──────────────────────────────────────────────────────────────────────────────
option(WITH_CGAL_TESTS "Build CGAL test suite without viewer/CLI (headless CI)" OFF)
option(WITH_CGAL       "Build conformallab_core CLI app + viewer + CGAL tests"  OFF)
option(WITH_VIEWER     "Build viewer library (libigl / GLFW / GLAD)"            OFF)

# WITH_CGAL_TESTS is a strict subset of WITH_CGAL — no viewer, no CLI.
# WITH_CGAL (full build) implies WITH_VIEWER.
if(WITH_CGAL AND NOT WITH_VIEWER)
    message(STATUS "WITH_CGAL implies WITH_VIEWER – enabling automatically.")
    set(WITH_VIEWER ON CACHE BOOL "" FORCE)
endif()

# Propagate Boost requirement for both CGAL modes.
if(WITH_CGAL OR WITH_CGAL_TESTS)
    find_package(Boost REQUIRED)
endif()

# ── Standard settings ──────────────────────────────────────────────────────────
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
  # ─── Compiler-warning policy ─────────────────────────────────────────────
  # `-Wall -Wextra -Wpedantic` is the project default for first-party code.
  # Vendored deps under code/deps/ get a separate, looser policy (handled
  # via per-target SYSTEM include marking when they are pulled in).
  #
  # `CONFORMALLAB_WARNINGS_AS_ERRORS=ON` flips on `-Werror` — used in CI's
  # promotion-track and by `scripts/quality/sanitizers.sh` to make sure no
  # new warning class slips in unannounced.  Off by default so regular
  # builds on slightly older toolchains aren't broken by a new GCC's
  # added warning.
  option(CONFORMALLAB_WARNINGS_AS_ERRORS
    "Treat compiler warnings as errors (-Werror)." OFF)

  add_compile_options(-Wall -Wextra -Wpedantic)

  if(CONFORMALLAB_WARNINGS_AS_ERRORS)
    add_compile_options(-Werror)
    message(STATUS "Warnings-as-errors mode active (-Werror).")
  endif()

  # AddressSanitizer only in Debug (gtest_discover_tests runs the binary at
  # configure time and hangs with ASan enabled).
  if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT BUILD_TESTING)
    add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
    add_link_options(-fsanitize=address)
  endif()
endif()

# ── GTest (always – tests are always built) ────────────────────────────────────
include(FetchContent)
include(CTest)
enable_testing()

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
set(INSTALL_GTEST          OFF CACHE BOOL "" FORCE)
set(BUILD_GMOCK            OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

# ── External deps (lazy tarball extraction) ────────────────────────────────────
add_subdirectory(deps)

# ── Viewer library (optional) ──────────────────────────────────────────────────
if(WITH_VIEWER)
    add_subdirectory(deps/glfw-3.4)

    add_library(glad STATIC
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/src/glad.c)
    target_include_directories(glad PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/include)

    add_library(viewer STATIC src/viewer/simple_viewer.cpp)
    target_include_directories(viewer PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-2.6.0/include
        ${CMAKE_CURRENT_SOURCE_DIR}/include
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-glad/include
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen-3.4.0/)
    target_link_libraries(viewer PUBLIC glad glfw)
endif()

# ── Core CLI app (optional, requires CGAL + Viewer) ───────────────────────────
if(WITH_CGAL)
    add_executable(${PROJECT_NAME} src/apps/v0/conformallab_cli.cpp)
    target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/single_includes
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen-3.4.0/
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/CGAL-6.1.1/include
        ${CMAKE_CURRENT_SOURCE_DIR}/deps/libigl-2.6.0/include
        ${Boost_INCLUDE_DIRS})
    target_include_directories(${PROJECT_NAME} PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/include)
    target_compile_definitions(${PROJECT_NAME} PRIVATE
        CGAL_DISABLE_GMP CGAL_DISABLE_MPFR)
    target_link_libraries(${PROJECT_NAME} PRIVATE viewer)
    set_target_properties(${PROJECT_NAME} PROPERTIES
        RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
endif()

# ── Example programs (require WITH_CGAL; viewer example also needs WITH_VIEWER) ─
if(WITH_CGAL)
    add_subdirectory(examples)
endif()

# ── Tests (always) ────────────────────────────────────────────────────────────
add_subdirectory(tests)

# ── Install target (header-only library) ──────────────────────────────────────
# Installs all public headers to <prefix>/include/conformallab/
# Usage from another CMake project:
#   cmake --install build --prefix /usr/local
#   target_include_directories(myapp PRIVATE /usr/local/include/conformallab)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/conformallab
        FILES_MATCHING PATTERN "*.hpp"
        PATTERN "* 2.*" EXCLUDE)   # exclude macOS Finder duplicates
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE
              ${CMAKE_CURRENT_SOURCE_DIR}/../CITATION.cff
        DESTINATION ${CMAKE_INSTALL_DATADIR}/conformallab)

# ── Doxygen documentation target (Phase 7.5) ──────────────────────────────────
# Generates HTML API documentation into doc/doxygen/html/.
# Usage:
#   cmake --build build --target doc
#   open doc/doxygen/html/index.html
#
# Optional dependency: install Doxygen via `brew install doxygen` (macOS) or
# `apt install doxygen graphviz` (Linux). The target is silently disabled
# if Doxygen is not found.
find_package(Doxygen QUIET)
if(DOXYGEN_FOUND)
    set(DOXYGEN_PROJECT_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..)
    add_custom_target(doc
        COMMAND ${DOXYGEN_EXECUTABLE} ${DOXYGEN_PROJECT_ROOT}/Doxyfile
        WORKING_DIRECTORY ${DOXYGEN_PROJECT_ROOT}
        COMMENT "Generating API documentation with Doxygen"
        VERBATIM)
    message(STATUS "Doxygen found: target 'doc' available (cmake --build build --target doc)")
else()
    message(STATUS "Doxygen not found — 'doc' target unavailable (install: brew/apt install doxygen)")
endif()
