# Copyright (c) 2026 The YAC Authors
#
# SPDX-License-Identifier: BSD-3-Clause

# Find Cython
execute_process(
  COMMAND ${Python3_EXECUTABLE} -c "import cython; print(cython.__version__)"
  OUTPUT_VARIABLE CYTHON_VERSION
  OUTPUT_STRIP_TRAILING_WHITESPACE
  RESULT_VARIABLE CYTHON_NOT_FOUND
)

if(CYTHON_NOT_FOUND)
  message(
    FATAL_ERROR "Cython not found. Please install it with: pip install cython"
  )
endif()

message(STATUS "Found Cython version: ${CYTHON_VERSION}")

# Determine output suffix for Python extensions
execute_process(
  COMMAND
    ${Python3_EXECUTABLE} -c
    "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))"
  OUTPUT_VARIABLE PYTHON_EXT_SUFFIX
  OUTPUT_STRIP_TRAILING_WHITESPACE
)

# Get Python version for site-packages path
set(PYTHON_VERSION_MAJOR_MINOR
    "${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}"
)

# Build the Cython source files
set(CORE_PYX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/src/core.pyx)
set(CORE_PYX_C ${CMAKE_CURRENT_BINARY_DIR}/core.c)

# Custom commands to generate C files from .pyx files
add_custom_command(
  OUTPUT ${CORE_PYX_C}
  COMMAND
    ${Python3_EXECUTABLE} -m cython -3 --cleanup 3 --module-name yac.core
    --output-file ${CORE_PYX_C} ${CORE_PYX_SOURCE}
  DEPENDS ${CORE_PYX_SOURCE}
  COMMENT "Cythonizing core.pyx to core.c"
)

# Build core extension module
python3_add_library(yac_python_core MODULE ${CORE_PYX_C})
set_target_properties(
  yac_python_core
  PROPERTIES OUTPUT_NAME "core"
             PREFIX ""
             SUFFIX "${PYTHON_EXT_SUFFIX}"
             LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/yac"
             INSTALL_RPATH_USE_LINK_PATH TRUE
             BUILD_RPATH_USE_ORIGIN TRUE
)
target_link_libraries(
  yac_python_core
  PRIVATE yac_core yac_utils Python3::Module Python3::NumPy MPI::MPI_C
)

target_compile_options(
  yac_python_core
  PRIVATE $<$<C_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-pedantic>
)

# Build MCI extension if enabled
if(YAC_ENABLE_MCI)
  set(YAC_PYX_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/yac.pyx)
  set(YAC_PYX_C ${CMAKE_CURRENT_BINARY_DIR}/_yac.c)

  add_custom_command(
    OUTPUT ${YAC_PYX_C}
    COMMAND
      ${Python3_EXECUTABLE} -m cython -3 --cleanup 3 --module-name yac._yac
      --output-file ${YAC_PYX_C} ${YAC_PYX_SOURCE}
    DEPENDS ${YAC_PYX_SOURCE}
    COMMENT "Cythonizing yac.pyx to _yac.c"
  )

  python3_add_library(yac_python_mci MODULE ${YAC_PYX_C})
  set_target_properties(
    yac_python_mci
    PROPERTIES OUTPUT_NAME "_yac"
               PREFIX ""
               SUFFIX "${PYTHON_EXT_SUFFIX}"
               LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/yac"
               INSTALL_RPATH_USE_LINK_PATH TRUE
               BUILD_RPATH_USE_ORIGIN TRUE
  )
  target_link_libraries(
    yac_python_mci PRIVATE yac_mci Python3::Module Python3::NumPy
  )
  target_compile_definitions(yac_python_mci PRIVATE YAC_CYTHON)
  target_compile_options(
    yac_python_mci
    PRIVATE $<$<C_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-pedantic>
  )

endif()

# Copy Python source files to build directory
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/yac)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/yac/examples)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/yac/utils)

# Copy/Configure __init__.py files
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/src/__init__.py.in
  ${CMAKE_CURRENT_BINARY_DIR}/yac/__init__.py
  @ONLY
)

configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/src/examples/__init__.py
  ${CMAKE_CURRENT_BINARY_DIR}/yac/examples/__init__.py
  COPYONLY
)
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/src/utils/__init__.py
  ${CMAKE_CURRENT_BINARY_DIR}/yac/utils/__init__.py
  COPYONLY
)

# Copy example and utility Python files
file(GLOB EXAMPLE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/examples/*.py")
foreach(example_file ${EXAMPLE_FILES})
  get_filename_component(filename ${example_file} NAME)
  if(NOT filename STREQUAL "__init__.py")
    configure_file(
      ${example_file}
      ${CMAKE_CURRENT_BINARY_DIR}/yac/examples/${filename}
      COPYONLY
    )
  endif()
endforeach()

file(GLOB UTILS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/utils/*.py")
foreach(utils_file ${UTILS_FILES})
  get_filename_component(filename ${utils_file} NAME)
  if(NOT filename STREQUAL "__init__.py")
    configure_file(
      ${utils_file} ${CMAKE_CURRENT_BINARY_DIR}/yac/utils/${filename} COPYONLY
    )
  endif()
endforeach()

if(DEFINED SKBUILD)
  # When built via pip/scikit-build-core, the package is installed into the
  # wheel:
  set(PYTHON_INSTALL_DIR yac)

  set_target_properties(
    yac_python_core PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE
  )
  install(TARGETS yac_python_core LIBRARY DESTINATION ${PYTHON_INSTALL_DIR})

  if(YAC_ENABLE_MCI)
    set_target_properties(
      yac_python_mci PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE
    )
    install(TARGETS yac_python_mci LIBRARY DESTINATION ${PYTHON_INSTALL_DIR})
  endif()

  install(
    DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/yac/
    DESTINATION ${PYTHON_INSTALL_DIR}
    FILES_MATCHING
    PATTERN "*.py"
  )
else()
  # Otherwise, the Python bindings are not installed by 'make install'. The
  # build directory contains the complete package together with a generated
  # setup.py, which the users can employ to install the bindings into a Python
  # environment of their choice (e.g. 'python -m pip install <builddir>').
  configure_file(setup.py.cmake_in ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY)

  # The modules are installed by copying them out of the build tree, therefore,
  # they must not rely on $ORIGIN-relative runtime paths.
  set(python_modules yac_python_core)
  if(YAC_ENABLE_MCI)
    list(APPEND python_modules yac_python_mci)
  endif()
  set_target_properties(
    ${python_modules} PROPERTIES BUILD_RPATH_USE_ORIGIN FALSE
  )
endif()
