# 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 --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 --module-name _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
  set(PYTHON_INSTALL_DIR yac)
else()
  # If a venv is found by find_package(Python3) this points in the venv
  set(PYTHON_INSTALL_DIR ${Python3_SITEARCH}/yac)
endif()

# Calculate RPATH for finding YAC libraries From:
# lib/python3.X/site-packages/yac/*.so To:   lib/ (or lib64) Path:
# $ORIGIN/../../<libdir>
if(NOT DEFINED SKBUILD)
  set(YAC_PYTHON_RPATH "$ORIGIN/../../..")
endif()

# Set INSTALL_RPATH for yac_python_core
if(NOT DEFINED SKBUILD)
  set_target_properties(
    yac_python_core PROPERTIES INSTALL_RPATH "${YAC_PYTHON_RPATH}"
  )
else()
  set_target_properties(
    yac_python_core PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE
  )
endif()

# Set INSTALL_RPATH for yac_python_mci if enabled
if(YAC_ENABLE_MCI)
  if(NOT DEFINED SKBUILD)
    set_target_properties(
      yac_python_mci PROPERTIES INSTALL_RPATH "${YAC_PYTHON_RPATH}"
    )
  else()
    set_target_properties(
      yac_python_mci PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE
    )
  endif()
endif()

install(TARGETS yac_python_core LIBRARY DESTINATION ${PYTHON_INSTALL_DIR})

if(YAC_ENABLE_MCI)
  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"
)

install(
  DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/
  DESTINATION ${PYTHON_INSTALL_DIR}
  FILES_MATCHING
  PATTERN "*.py"
  PATTERN "__init__.py" EXCLUDE
)
