
cmake_minimum_required(VERSION 3.25)

project(pycanha_core_bindings LANGUAGES CXX)

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

# Emit compile_commands.json so editors / clangd can resolve nanobind, Eigen and
# pycanha-core headers (the bindings *.hpp otherwise flood with unresolved-include
# errors in the IDE even though the build is clean).
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

find_package(Python COMPONENTS Interpreter Development REQUIRED)
find_package(nanobind CONFIG REQUIRED)
find_package(pycanha-core CONFIG REQUIRED)

nanobind_add_module(pycanha_core MODULE
    pycanha-core-wrapper.cpp
)

target_link_libraries(pycanha_core PRIVATE pycanha-core::pycanha-core)

# So that one binding header can include another by its "bindings/<area>/..."
# path. Without it only the wrapper, which sits in this directory, can use that
# spelling: GCC resolves a quoted include against the including file's own
# directory, not against the translation unit's.
target_include_directories(pycanha_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
set_target_properties(pycanha_core PROPERTIES
    BUILD_RPATH "\$ORIGIN/../../.."
    INSTALL_RPATH "\$ORIGIN/../../.."
)

install(TARGETS pycanha_core DESTINATION pycanha_core)

# Install runtime Python files (__init__.py, py.typed)
install(
    DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../pycanha_core/
    DESTINATION pycanha_core
    FILES_MATCHING
    PATTERN "*.py"
    PATTERN "py.typed"
)

# Type stubs: either generate from compiled module or use pregenerated ones
set(PYCANHA_PREGENERATED_STUBS_DIR "" CACHE PATH
    "Path to pregenerated .pyi stubs. If set, skip nanobind stub generation.")

if(PYCANHA_PREGENERATED_STUBS_DIR)
    message(STATUS "Using pregenerated stubs from: ${PYCANHA_PREGENERATED_STUBS_DIR}")
    install(
        DIRECTORY "${PYCANHA_PREGENERATED_STUBS_DIR}/"
        DESTINATION pycanha_core
        FILES_MATCHING
        PATTERN "*.pyi"
        PATTERN "py.typed"
    )
else()
    message(STATUS "Generating stubs with nanobind")
    set(STUB_DIR "${CMAKE_CURRENT_BINARY_DIR}/stubs")

    nanobind_add_stub(
        pycanha_core_init_stub
        MODULE pycanha_core
        OUTPUT "${STUB_DIR}/__init__.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
        MARKER_FILE "${STUB_DIR}/py.typed"
    )

    nanobind_add_stub(
        pycanha_core_gmm_stub
        MODULE pycanha_core.gmm
        OUTPUT "${STUB_DIR}/gmm.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_tmm_stub
        MODULE pycanha_core.tmm
        OUTPUT "${STUB_DIR}/tmm.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_parameters_stub
        MODULE pycanha_core.parameters
        OUTPUT "${STUB_DIR}/parameters.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_solvers_stub
        MODULE pycanha_core.solvers
        OUTPUT "${STUB_DIR}/solvers.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_radiative_stub
        MODULE pycanha_core.radiative
        OUTPUT "${STUB_DIR}/radiative.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_conduction_stub
        MODULE pycanha_core.conduction
        OUTPUT "${STUB_DIR}/conduction.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    nanobind_add_stub(
        pycanha_core_log_stub
        MODULE pycanha_core.log
        OUTPUT "${STUB_DIR}/log.pyi"
        PYTHON_PATH "$<TARGET_FILE_DIR:pycanha_core>"
        DEPENDS pycanha_core
    )

    install(
        DIRECTORY "${STUB_DIR}/"
        DESTINATION pycanha_core
        FILES_MATCHING
        PATTERN "*.pyi"
        PATTERN "py.typed"
    )
endif()

