# Python bindings using pybind11

# If provided via environment (cibuildwheel), hint CMake with explicit Python paths
if(NOT DEFINED Python3_EXECUTABLE AND DEFINED ENV{Python3_EXECUTABLE})
    set(Python3_EXECUTABLE "$ENV{Python3_EXECUTABLE}")
endif()
if(NOT DEFINED Python3_ROOT_DIR AND DEFINED ENV{Python3_ROOT_DIR})
    set(Python3_ROOT_DIR "$ENV{Python3_ROOT_DIR}")
endif()
if(NOT DEFINED Python3_LIBRARY AND DEFINED ENV{Python3_LIBRARY})
    set(Python3_LIBRARY "$ENV{Python3_LIBRARY}")
    set(Python3_LIBRARIES "$ENV{Python3_LIBRARY}")
endif()
if(NOT DEFINED Python3_INCLUDE_DIR AND DEFINED ENV{Python3_INCLUDE_DIR})
    set(Python3_INCLUDE_DIR "$ENV{Python3_INCLUDE_DIR}")
endif()

# Derive libpython path from the interpreter when possible to help FindPython locate Development/Embed components
if(DEFINED Python3_EXECUTABLE)
    execute_process(
        COMMAND ${Python3_EXECUTABLE} -c "import sysconfig; libdir=sysconfig.get_config_var('LIBDIR') or ''; soname=sysconfig.get_config_var('INSTSONAME') or ''; incdir=sysconfig.get_paths().get('include', '') or ''; print(libdir); print(soname); print(incdir)"
        OUTPUT_VARIABLE PY_LIBINFO
        OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    string(REGEX MATCHALL "[^\n]+" PY_LIBINFO_LIST "${PY_LIBINFO}")
    list(LENGTH PY_LIBINFO_LIST PY_LIBINFO_LEN)
    if(PY_LIBINFO_LEN GREATER 2)
        list(GET PY_LIBINFO_LIST 0 PY_LIBDIR)
        list(GET PY_LIBINFO_LIST 1 PY_LIBSONAME)
        list(GET PY_LIBINFO_LIST 2 PY_INCDIR)
        if(NOT DEFINED Python3_LIBRARY AND PY_LIBDIR AND PY_LIBSONAME)
            set(Python3_LIBRARY "${PY_LIBDIR}/${PY_LIBSONAME}" CACHE FILEPATH "")
            set(Python3_LIBRARIES "${Python3_LIBRARY}" CACHE FILEPATH "")
        endif()
        if(NOT DEFINED Python3_INCLUDE_DIR AND PY_INCDIR)
            set(Python3_INCLUDE_DIR "${PY_INCDIR}" CACHE PATH "")
        endif()
    endif()
endif()

set(Python3_FIND_IMPLEMENTATIONS "CPython")
set(Python3_FIND_STRATEGY "LOCATION")
set(Python3_FIND_UNVERSIONED_NAMES "FIRST")

find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)

# Prefer pybind11 provided by the build environment (e.g., installed via pip)
find_package(pybind11 CONFIG QUIET)
if(NOT pybind11_FOUND)
    include(FetchContent)
    FetchContent_Declare(
        pybind11
        GIT_REPOSITORY https://github.com/pybind/pybind11.git
        GIT_TAG v2.12.0
        GIT_SHALLOW TRUE
    )
    FetchContent_MakeAvailable(pybind11)
endif()

# Create the Python module (high-performance API)
pybind11_add_module(_pulsim
    NO_EXTRAS
    bindings.cpp
)

target_link_libraries(_pulsim
    PRIVATE
        pulsim::core
        pulsim::pulsim
)
if(APPLE)
    target_compile_options(_pulsim PRIVATE -fvisibility=hidden -fvisibility-inlines-hidden)
endif()
if(COMMAND pulsim_apply_target_defaults)
    pulsim_apply_target_defaults(_pulsim)
endif()

# Set the output name to match Python conventions
set_target_properties(_pulsim PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/python/pulsim"
)

# Copy Python wrapper module
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/__init__.py
    ${CMAKE_BINARY_DIR}/python/pulsim/__init__.py
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/netlist.py
    ${CMAKE_BINARY_DIR}/python/pulsim/netlist.py
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/signal_evaluator.py
    ${CMAKE_BINARY_DIR}/python/pulsim/signal_evaluator.py
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/__init__.pyi
    ${CMAKE_BINARY_DIR}/python/pulsim/__init__.pyi
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/post_processing.py
    ${CMAKE_BINARY_DIR}/python/pulsim/post_processing.py
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/cblock.py
    ${CMAKE_BINARY_DIR}/python/pulsim/cblock.py
    COPYONLY
)
configure_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/pulsim/magnetic_core.py
    ${CMAKE_BINARY_DIR}/python/pulsim/magnetic_core.py
    COPYONLY
)

# Package CBlock ABI header with the Python module so compile_cblock() works
# from installed wheels, not only from source checkouts.
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/python/pulsim/include/pulsim/v1")
configure_file(
    ${CMAKE_SOURCE_DIR}/core/include/pulsim/v1/cblock_abi.h
    ${CMAKE_BINARY_DIR}/python/pulsim/include/pulsim/v1/cblock_abi.h
    COPYONLY
)

# Install targets
install(TARGETS _pulsim
    LIBRARY DESTINATION pulsim
)

install(FILES
    pulsim/__init__.py
    pulsim/__init__.pyi
    pulsim/netlist.py
    pulsim/signal_evaluator.py
    pulsim/post_processing.py
    pulsim/cblock.py
    pulsim/magnetic_core.py
    DESTINATION pulsim
)

install(FILES
    ${CMAKE_SOURCE_DIR}/core/include/pulsim/v1/cblock_abi.h
    DESTINATION pulsim/include/pulsim/v1
)
