cmake_minimum_required(VERSION 3.15)
project(py-bipe LANGUAGES C CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

if(MSVC)
    add_compile_definitions(NOMINMAX)
    add_compile_definitions(popen=_popen)
    add_compile_definitions(pclose=_pclose)
    add_compile_options(/W0)
endif()

if(POLICY CMP0097)
    cmake_policy(SET CMP0097 NEW)
endif()

# -----------------------------------------------------------------------------
# 1. Fetch (or reuse) bipe
# -----------------------------------------------------------------------------
include(FetchContent)
set(FETCHCONTENT_BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_deps" CACHE PATH "Directory for FetchContent" FORCE)

set(BIPE_LOCAL_PATH "" CACHE PATH "Path to a local bipe source directory (skips FetchContent clone)")
if (NOT BIPE_LOCAL_PATH AND EXISTS "/home/jm/dev/cnrs/d4/bipe/CMakeLists.txt")
    set(BIPE_LOCAL_PATH "/home/jm/dev/cnrs/d4/bipe")
endif()

if (BIPE_LOCAL_PATH AND EXISTS "${BIPE_LOCAL_PATH}/CMakeLists.txt")
    message(STATUS "Using local bipe source at: ${BIPE_LOCAL_PATH}")
    FetchContent_Declare(
        bipe
        SOURCE_DIR "${BIPE_LOCAL_PATH}"
    )
else()
    if (DEFINED ENV{GITLAB_TOKEN_LOGICAL} AND NOT DEFINED ENV{GITLAB_TOKEN})
        set(ENV{GITLAB_TOKEN} "$ENV{GITLAB_TOKEN_LOGICAL}")
    elseif (DEFINED ENV{GITLAB_TOKEN_BIPE} AND NOT DEFINED ENV{GITLAB_TOKEN})
        set(ENV{GITLAB_TOKEN} "$ENV{GITLAB_TOKEN_BIPE}")
    endif()

    if (DEFINED ENV{GITLAB_TOKEN} AND NOT DEFINED ENV{GITLAB_TOKEN_LOGICAL})
        set(ENV{GITLAB_TOKEN_LOGICAL} "$ENV{GITLAB_TOKEN}")
    elseif (DEFINED ENV{GITLAB_TOKEN_BIPE} AND NOT DEFINED ENV{GITLAB_TOKEN_LOGICAL})
        set(ENV{GITLAB_TOKEN_LOGICAL} "$ENV{GITLAB_TOKEN_BIPE}")
    endif()

    if (DEFINED ENV{BIPE_GIT_URL} AND NOT "$ENV{BIPE_GIT_URL}" STREQUAL "")
        set(BIPE_GIT_URL "$ENV{BIPE_GIT_URL}")
        message(STATUS "Using custom bipe Git URL from environment variable: ${BIPE_GIT_URL}")
    elseif (DEFINED ENV{GITLAB_TOKEN_BIPE})
        set(BIPE_GIT_URL "https://oauth2:$ENV{GITLAB_TOKEN_BIPE}@gitlab.univ-artois.fr/logical/bipe.git")
        message(STATUS "Using authenticated GitLab URL for bipe (token from env GITLAB_TOKEN_BIPE)")
    elseif (DEFINED ENV{GITLAB_TOKEN_LOGICAL})
        set(BIPE_GIT_URL "https://oauth2:$ENV{GITLAB_TOKEN_LOGICAL}@gitlab.univ-artois.fr/logical/bipe.git")
        message(STATUS "Using authenticated GitLab URL for bipe (token from env GITLAB_TOKEN_LOGICAL)")
    else()
        set(BIPE_GIT_URL "https://gitlab.univ-artois.fr/logical/bipe.git")
        message(STATUS "No GITLAB_TOKEN_BIPE or GITLAB_TOKEN_LOGICAL env variable set — using unauthenticated URL for bipe")
    endif()

    set(BIPE_GIT_TAG "main" CACHE STRING "Git tag/branch for fetching bipe")
    if (DEFINED ENV{BIPE_GIT_TAG} AND NOT "$ENV{BIPE_GIT_TAG}" STREQUAL "")
        set(BIPE_GIT_TAG "$ENV{BIPE_GIT_TAG}")
    endif()
    message(STATUS "bipe Git tag/branch set to: ${BIPE_GIT_TAG}")

    FetchContent_Declare(
        bipe
        GIT_REPOSITORY ${BIPE_GIT_URL}
        GIT_TAG        ${BIPE_GIT_TAG}
        GIT_SHALLOW    TRUE
        GIT_SUBMODULES ""
    )
endif()

# Fetch and integrate bipe as a subdirectory
FetchContent_GetProperties(bipe)
if(NOT bipe_POPULATED)
    if(POLICY CMP0169)
        cmake_policy(SET CMP0169 OLD)
    endif()
    FetchContent_Populate(bipe)
    add_subdirectory(${bipe_SOURCE_DIR} ${bipe_BINARY_DIR} SYSTEM)
    if(TARGET cadical)
        target_compile_definitions(cadical PRIVATE NCLOSEFROM)
    endif()
    if(MSVC)
        foreach(t bipe cadical glucose optree)
            if(TARGET ${t})
                set_target_properties(${t} PROPERTIES COMPILE_OPTIONS "/W0;/wd4244;/wd4267;/wd4018;/wd4305")
            endif()
        endforeach()
    endif()
endif()

message(STATUS "bipe source dir: ${bipe_SOURCE_DIR}")
message(STATUS "bipe binary dir: ${bipe_BINARY_DIR}")

# -----------------------------------------------------------------------------
# 2. Setup Nanobind & Python & Dependencies
# -----------------------------------------------------------------------------
find_package(Python 3.8 COMPONENTS Interpreter Development.Module REQUIRED)

find_package(nanobind CONFIG QUIET)
if (NOT nanobind_FOUND)
    message(STATUS "nanobind not found. Fetching it...")
    FetchContent_Declare(
        nanobind
        GIT_REPOSITORY https://github.com/wjakob/nanobind.git
        GIT_TAG        v2.0.0
    )
    FetchContent_MakeAvailable(nanobind)
endif()

find_package(nlohmann_json QUIET)
if (NOT nlohmann_json_FOUND)
    message(STATUS "nlohmann_json not found. Fetching it...")
    FetchContent_Declare(
        json
        GIT_REPOSITORY https://github.com/nlohmann/json.git
        GIT_TAG        v3.11.3
    )
    FetchContent_MakeAvailable(json)
endif()

# -----------------------------------------------------------------------------
# 3. Auto-generate C++ definitions and Python bindings
# -----------------------------------------------------------------------------
add_custom_command(
    OUTPUT
        "${CMAKE_CURRENT_SOURCE_DIR}/src/Binding.hpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/generated_bindings.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/src/generated_runner_bindings.cpp"
    COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_binding_hpp.py" "${bipe_SOURCE_DIR}"
    COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_bindings.py" "${bipe_SOURCE_DIR}"
    COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_runner_bindings.py" "${bipe_SOURCE_DIR}"
    DEPENDS
        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_binding_hpp.py"
        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_bindings.py"
        "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_runner_bindings.py"
    COMMENT "Auto-generating options C++ definitions and Python bindings for bipe..."
    VERBATIM
)

# -----------------------------------------------------------------------------
# 4. Define Nanobind Module
# -----------------------------------------------------------------------------
set(BIPE_PARSER_SRC "${bipe_SOURCE_DIR}/c++/src/ParserDimacs.cpp")

nanobind_add_module(
    _py_bipe
    NB_STATIC
    src/wrapper.cpp
    "${CMAKE_CURRENT_SOURCE_DIR}/src/generated_bindings.cpp"
    "${CMAKE_CURRENT_SOURCE_DIR}/src/generated_runner_bindings.cpp"
    "${BIPE_PARSER_SRC}"
)

# Link against bipe library and JSON
target_link_libraries(_py_bipe PRIVATE bipe nlohmann_json::nlohmann_json)

if(WIN32)
    target_link_libraries(_py_bipe PRIVATE psapi)
endif()

if(MSVC)
    set_target_properties(_py_bipe PROPERTIES COMPILE_OPTIONS "/W0;/wd4244;/wd4267;/wd4018;/wd4305")
endif()

# Include paths
target_include_directories(_py_bipe PRIVATE
    "${CMAKE_CURRENT_SOURCE_DIR}/src"
    "${bipe_SOURCE_DIR}"
    "${bipe_SOURCE_DIR}/src"
    "${bipe_SOURCE_DIR}/c++"
    "${bipe_SOURCE_DIR}/c++/src"
    "${bipe_SOURCE_DIR}/3rdParty/glucose-3.0"
    "${bipe_SOURCE_DIR}/3rdParty/cadical/src"
)
install(TARGETS _py_bipe DESTINATION pybipe)

# Generate Python autocomplete/stub files (.pyi) post-build
add_custom_command(
    TARGET _py_bipe POST_BUILD
    COMMAND "${Python_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/scripts/generate_stubs.py" _py_bipe "${CMAKE_CURRENT_BINARY_DIR}"
    WORKING_DIRECTORY $<TARGET_FILE_DIR:_py_bipe>
    COMMENT "Generating autocomplete/type stub file (_py_bipe.pyi)..."
    VERBATIM
)

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/_py_bipe.pyi" DESTINATION pybipe OPTIONAL)
