cmake_minimum_required(VERSION 3.15)
project(libsemigroups_julia CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Prevent FindJulia.cmake from running if Julia paths are provided
if(DEFINED Julia_EXECUTABLE AND DEFINED Julia_INCLUDE_DIRS AND DEFINED Julia_LIBRARY_DIR)
    set(Julia_FOUND TRUE)
    message(STATUS "Using provided Julia paths")
    message(STATUS "  Julia_EXECUTABLE: ${Julia_EXECUTABLE}")
    message(STATUS "  Julia_INCLUDE_DIRS: ${Julia_INCLUDE_DIRS}")
    message(STATUS "  Julia_LIBRARY_DIR: ${Julia_LIBRARY_DIR}")
endif()

# Find JlCxx (CxxWrap C++ library)
find_package(JlCxx REQUIRED)

# Find libsemigroups - prefer JLL paths if provided, fall back to pkg-config
if(DEFINED LIBSEMIGROUPS_INCLUDE_DIR AND DEFINED LIBSEMIGROUPS_LIBRARY_DIR)
    message(STATUS "Using libsemigroups from JLL:")
    message(STATUS "  include dir: ${LIBSEMIGROUPS_INCLUDE_DIR}")
    message(STATUS "  library dir: ${LIBSEMIGROUPS_LIBRARY_DIR}")
    # JLL bundles fmt/rx/etc headers under include/libsemigroups/, so we need both paths
    set(LIBSEMIGROUPS_INCLUDE_DIRS "${LIBSEMIGROUPS_INCLUDE_DIR};${LIBSEMIGROUPS_INCLUDE_DIR}/libsemigroups")
    set(LIBSEMIGROUPS_LIBRARY_DIRS "${LIBSEMIGROUPS_LIBRARY_DIR}")
    set(LIBSEMIGROUPS_LIBRARIES "semigroups")
    set(LIBSEMIGROUPS_INCLUDEDIR "${LIBSEMIGROUPS_INCLUDE_DIR}")
else()
    # Fall back to system-installed libsemigroups via pkg-config
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(LIBSEMIGROUPS REQUIRED libsemigroups)
    pkg_get_variable(LIBSEMIGROUPS_INCLUDEDIR libsemigroups includedir)
    message(STATUS "Using system libsemigroups via pkg-config")
endif()

message(STATUS "JlCxx found at: ${JlCxx_DIR}")
message(STATUS "libsemigroups include dirs: ${LIBSEMIGROUPS_INCLUDE_DIRS}")
message(STATUS "libsemigroups library dirs: ${LIBSEMIGROUPS_LIBRARY_DIRS}")
message(STATUS "libsemigroups libraries: ${LIBSEMIGROUPS_LIBRARIES}")

# Build the shared library
add_library(libsemigroups_julia SHARED
    libsemigroups_julia.cpp
    bmat8.cpp
    cong-common.cpp
    constants.cpp
    froidure-pin-base.cpp
    froidure-pin.cpp
    order.cpp
    report.cpp
    runner.cpp
    transf.cpp
    word-graph.cpp
    word-range.cpp
    paths.cpp
    presentation.cpp
    presentation-examples.cpp
    knuth-bendix.cpp
    todd-coxeter.cpp
    kambites.cpp
    congruence.cpp
    to-cong.cpp
)

# Include directories
target_include_directories(libsemigroups_julia PRIVATE
  ${LIBSEMIGROUPS_INCLUDE_DIRS}
)

# Link directories
target_link_directories(libsemigroups_julia PRIVATE
    ${LIBSEMIGROUPS_LIBRARY_DIRS}
    ${Julia_LIBRARY_DIR}
)

# Link libraries
target_link_libraries(libsemigroups_julia
    JlCxx::cxxwrap_julia
    JlCxx::cxxwrap_julia_stl
    ${LIBSEMIGROUPS_LIBRARIES}
    julia
)

# Compiler flags
target_compile_options(libsemigroups_julia PRIVATE
    "-I${LIBSEMIGROUPS_INCLUDEDIR}"
    -fno-char8_t  # Work around C++20 char8_t issues with fmt in libsemigroups
    # Silence noisy upstream warnings from libsemigroups iterator templates
    # under C++20's reversed-operator rules. The semantics are unambiguous;
    # only Clang/AppleClang emit this warning.
    $<$<CXX_COMPILER_ID:Clang,AppleClang>:-Wno-ambiguous-reversed-operator>
)

# Set RPATH to find libsemigroups at runtime
if(DEFINED LIBSEMIGROUPS_LIBRARY_DIR)
    set_target_properties(libsemigroups_julia PROPERTIES
        INSTALL_RPATH "${LIBSEMIGROUPS_LIBRARY_DIR}"
        BUILD_RPATH "${LIBSEMIGROUPS_LIBRARY_DIR}"
    )
endif()

# Set output name - removes the extra "lib" prefix CMake would add
set_target_properties(libsemigroups_julia PROPERTIES
    PREFIX ""
    OUTPUT_NAME "libsemigroups_julia"
)

# Installation rules
install(TARGETS libsemigroups_julia
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib
)
