cmake_minimum_required(VERSION 3.18...3.30)

project(fscatter
  VERSION 1.0
  DESCRIPTION "jscatter.fscatter module"
  LANGUAGES C Fortran)

# Modern target extraction: Requires CMake 3.18+ to natively expose Python3::NumPy
find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module NumPy)
find_package(OpenMP COMPONENTS Fortran)

# Extract F2PY header paths securely for custom command tracking
execute_process(
  COMMAND "${Python3_EXECUTABLE}" -c "import numpy.f2py; print(numpy.f2py.get_include())"
  OUTPUT_VARIABLE F2PY_INCLUDE_DIR
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
# changes path separator on Windows , does nothing on Linux
cmake_path(CONVERT "${F2PY_INCLUDE_DIR}" TO_CMAKE_PATH_LIST F2PY_INCLUDE_DIR)

include(CMakePrintHelpers)
cmake_print_variables(Python3_INCLUDE_DIRS)
cmake_print_variables(F2PY_INCLUDE_DIR)
cmake_print_variables(Python3_NumPy_INCLUDE_DIRS)
cmake_print_variables(CMAKE_CURRENT_BINARY_DIR)
cmake_print_variables(CMAKE_SOURCE_DIR)
cmake_print_variables(Python3_EXECUTABLE)
cmake_print_variables(CMAKE_PROJECT_NAME)
cmake_print_variables(GFORTRANLIB)
cmake_print_variables(CMAKE_LIBRARY_PATH)

set(f2py_module_name "fscatter")
set(fortran_src_files ${CMAKE_SOURCE_DIR}/a_typesandconstants.f95
                     ${CMAKE_SOURCE_DIR}/a_halton.f95
                     ${CMAKE_SOURCE_DIR}/a_qshep3d.f95
                     ${CMAKE_SOURCE_DIR}/autil.f95
                     ${CMAKE_SOURCE_DIR}/erfr.f90
                     ${CMAKE_SOURCE_DIR}/cloud.f95
                     ${CMAKE_SOURCE_DIR}/dynamic.f95)

set(f2py_module_c "${f2py_module_name}module.c")

# ============================================================================
# Wrapper Generation Block
# ============================================================================
add_custom_command(
  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}"
         "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers.f"
         "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers2.f90"
  COMMAND ${Python3_EXECUTABLE} -m numpy.f2py
          ${fortran_src_files}
          -m "${f2py_module_name}"
          --lower
  DEPENDS ${fortran_src_files}
  WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)

# ============================================================================
# Main Target Module Declaration
# ============================================================================
Python3_add_library(fscatter MODULE WITH_SOABI
  "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_c}"
  "${F2PY_INCLUDE_DIR}/fortranobject.c"
  "${fortran_src_files}"
  "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers.f"
  "${CMAKE_CURRENT_BINARY_DIR}/${f2py_module_name}-f2pywrappers2.f90"
)

set_target_properties(fscatter PROPERTIES
    LINKER_LANGUAGE C
    C_STANDARD 99
    C_STANDARD_REQUIRED ON
    POSITION_INDEPENDENT_CODE ON
)

if(APPLE)
  set_target_properties(fscatter PROPERTIES OSX_ARCHITECTURES "arm64")

  # Protects macOS CI by ensuring __npy_f2py_ARRAY_API skips 12-bit optimization crashes
  target_compile_options(fscatter PRIVATE
      $<$<COMPILE_LANGUAGE:Fortran>:-fPIC -fno-common>
      $<$<COMPILE_LANGUAGE:C>:-fPIC -fvisibility=default -fno-common>
  )

  target_link_options(fscatter PRIVATE "-undefined" "dynamic_lookup")

elseif(WIN32)
  target_compile_definitions(fscatter PRIVATE FORTRAN_EXPORTS)
endif()

# ============================================================================
# Modern Target Linking (Handles includes natively without empty string bugs)
# ============================================================================
target_link_libraries(fscatter PRIVATE Python3::Module)
target_link_libraries(fscatter PRIVATE Python3::NumPy)
target_link_libraries(fscatter PRIVATE OpenMP::OpenMP_Fortran)

# Explicit fallback inclusions for custom f2py generation tracks
target_include_directories(fscatter PRIVATE "${F2PY_INCLUDE_DIR}")
target_include_directories(fscatter PRIVATE "${OpenMP_Fortran_INCLUDE_DIRS}")

if(MSVC OR MSYS OR MINGW)
  target_link_libraries(fscatter PRIVATE libgfortran libgomp KERNEL32)
endif()