cmake_minimum_required(VERSION 3.20)
project(HVRT VERSION 1.0.0 LANGUAGES CXX)

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

# --------------------------------------------------------------------------
# Compiler flags
# --------------------------------------------------------------------------
if(MSVC)
    add_compile_options(/O2 /W3)
    add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
    add_compile_options(-O3 -Wall -Wextra -Wno-unused-parameter)
endif()

# Optional: enable -march=native / /arch:AVX2 for AVX2 SIMD auto-vectorization.
# OFF by default so CI wheels remain cross-platform. Enable locally for max speed.
option(HVRT_NATIVE_ARCH "Use -march=native / /arch:AVX2 for AVX2 auto-vectorization" OFF)
if(HVRT_NATIVE_ARCH)
    if(MSVC)
        add_compile_options(/arch:AVX2)
    else()
        add_compile_options(-march=native)
    endif()
endif()

# --------------------------------------------------------------------------
# OpenMP (soft dependency — builds without it; enables scatter parallelism)
# --------------------------------------------------------------------------
find_package(OpenMP)

# --------------------------------------------------------------------------
# FetchContent dependencies
# --------------------------------------------------------------------------
include(FetchContent)

FetchContent_Declare(
    Eigen
    URL      https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.bz2
    URL_HASH SHA256=b4c198460eba6f28d34894e3a5710998818515104d6e74e5cc331ce31e46e626
    EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(Eigen)

# pybind11 — prefer find_package (scikit-build-core injects the path
# automatically; for local CMake builds: pip install pybind11).
# Falls back to FetchContent v3.0.0 when not found (e.g. offline builds).
find_package(pybind11 CONFIG QUIET)
if(NOT pybind11_FOUND)
    message(STATUS "pybind11 not found via find_package; fetching v3.0.0 from GitHub")
    FetchContent_Declare(
        pybind11
        URL      https://github.com/pybind/pybind11/archive/refs/tags/v3.0.0.tar.gz
        URL_HASH SHA256=bb4c986c4c6d579486deba42d0e512ab4385ba03e3bb2feabc0ddfc1f8b7b5e4
    )
    FetchContent_MakeAvailable(pybind11)
endif()

# --------------------------------------------------------------------------
# hvrt_core — static library (no Python dependency)
# --------------------------------------------------------------------------
add_library(hvrt_core STATIC
    src/whitener.cpp
    src/target.cpp
    src/binner.cpp
    src/tree.cpp
    src/reduce.cpp
    src/expand.cpp
    src/hvrt.cpp
)

target_include_directories(hvrt_core PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/pcg
)

target_link_libraries(hvrt_core PUBLIC Eigen3::Eigen)
if(OpenMP_CXX_FOUND)
    target_link_libraries(hvrt_core PUBLIC OpenMP::OpenMP_CXX)
    message(STATUS "OpenMP found — scatter parallelism enabled")
else()
    message(STATUS "OpenMP not found — single-threaded scatter (still cache-optimised)")
endif()
set_property(TARGET hvrt_core PROPERTY POSITION_INDEPENDENT_CODE ON)

# --------------------------------------------------------------------------
# _hvrt — pybind11 extension module
# --------------------------------------------------------------------------
pybind11_add_module(_hvrt_cpp python/bindings.cpp)
target_link_libraries(_hvrt_cpp PRIVATE hvrt_core)
target_include_directories(_hvrt_cpp PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/pcg
)

# Install into the hvrt package directory so it's importable as hvrt._hvrt_cpp
# SKBUILD_PROJECT_NAME is set by scikit-build-core; falls back gracefully otherwise.
if(DEFINED SKBUILD)
    install(TARGETS _hvrt_cpp DESTINATION hvrt)
endif()

# --------------------------------------------------------------------------
# Tests (optional — requires Catch2)
# --------------------------------------------------------------------------
option(HVRT_BUILD_TESTS "Build C++ unit tests" OFF)
if(HVRT_BUILD_TESTS)
    FetchContent_Declare(
        Catch2
        GIT_REPOSITORY https://github.com/catchorg/Catch2.git
        GIT_TAG        v3.4.0
        GIT_SHALLOW    TRUE
    )
    FetchContent_MakeAvailable(Catch2)

    add_executable(hvrt_tests tests/test_correctness.cpp)
    target_link_libraries(hvrt_tests PRIVATE hvrt_core Catch2::Catch2WithMain)
    target_include_directories(hvrt_tests PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/include
        ${CMAKE_CURRENT_SOURCE_DIR}/third_party/pcg
    )
endif()
