﻿cmake_minimum_required(VERSION 3.20)
project(cf_pipeline_engine LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)

include(CTest)

get_filename_component(_CF_REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../.." ABSOLUTE)
include("${_CF_REPO_ROOT}/tools/cmake/cf_contracts_include.cmake")

set(TYPE_REGISTRY_V0_SOURCE_PATH
  "${CMAKE_CURRENT_SOURCE_DIR}/resources/type_registry.v0.json"
)

include(FetchContent)
FetchContent_Declare(
  nlohmann_json
  GIT_REPOSITORY https://github.com/nlohmann/json.git
  GIT_TAG v3.11.2
)
FetchContent_MakeAvailable(nlohmann_json)

add_library(cf_pipeline_v2_utils STATIC
  src/common/sha256.cpp
  src/common/type_registry.cc
  src/compiler/rdf_loader.cpp
  src/compiler/signature.cpp
)

target_include_directories(cf_pipeline_v2_utils PUBLIC
  ${CF_CONTRACTS_INCLUDE}
  ${CMAKE_CURRENT_SOURCE_DIR}/src
)

set(TYPE_REGISTRY_V0_FILENAME "type_registry.v0.json")

if (NOT EXISTS "${TYPE_REGISTRY_V0_SOURCE_PATH}")
  message(FATAL_ERROR "Bundled type_registry.v0.json not found in '${TYPE_REGISTRY_V0_SOURCE_PATH}'.")
endif()

file(TO_CMAKE_PATH "${TYPE_REGISTRY_V0_SOURCE_PATH}" TYPE_REGISTRY_V0_SOURCE_PATH)

target_compile_definitions(cf_pipeline_v2_utils PRIVATE
  CF_TYPE_REGISTRY_V0_PATH="${TYPE_REGISTRY_V0_SOURCE_PATH}"
  CF_TYPE_REGISTRY_V0_FILENAME="${TYPE_REGISTRY_V0_FILENAME}"
)

target_link_libraries(cf_pipeline_v2_utils PUBLIC nlohmann_json::nlohmann_json)

add_executable(cf_siggen EXCLUDE_FROM_ALL tools/cf_siggen_main.cpp)
target_include_directories(cf_siggen PRIVATE
  ${CF_CONTRACTS_INCLUDE}
  ${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(cf_siggen PRIVATE cf_pipeline_v2_utils)

set(GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated)
file(MAKE_DIRECTORY ${GENERATED_DIR})
execute_process(
  COMMAND ${Python3_EXECUTABLE} -c
          "import inspect, pathlib, cf_step_tooling.siggen as sig, cf_step_tooling._signatures as impl, cf_step_tooling._step_document as doc, cf_step_tooling._rdf as rdf; print(pathlib.Path(inspect.getsourcefile(sig)).resolve()); print(pathlib.Path(inspect.getsourcefile(impl)).resolve()); print(pathlib.Path(inspect.getsourcefile(doc)).resolve()); print(pathlib.Path(inspect.getsourcefile(rdf)).resolve())"
  OUTPUT_VARIABLE CF_SIGGEN_DEPENDENCY_OUTPUT
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REPLACE "\r\n" "\n" CF_SIGGEN_DEPENDENCY_OUTPUT "${CF_SIGGEN_DEPENDENCY_OUTPUT}")
string(REPLACE "\n" ";" CF_SIGGEN_DEPENDENCIES "${CF_SIGGEN_DEPENDENCY_OUTPUT}")

add_custom_command(
  OUTPUT ${GENERATED_DIR}/cf_test_signature_hashes.h
  COMMAND ${Python3_EXECUTABLE} -m cf_step_tooling.siggen
          --steps ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_steps.nq
          --out ${GENERATED_DIR}/cf_test_signature_hashes.h
          --scratch
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_steps.nq ${CF_SIGGEN_DEPENDENCIES}
  COMMENT "Generating test signature hashes"
  VERBATIM
)

add_library(cf_pipeline_v2_core STATIC
  src/compiler/pipeline_parser.cpp
  src/compiler/plan_builder.cpp
  src/plugin_loader/plugin_loader.cpp
  src/runtime_contract/dynamic_contract_loader.cpp
  src/runtime_contract/datahive_sink_loader.cpp
  src/runtime_contract/opcua_owner_loader.cpp
  src/runtime_contract/step_runtime_loader.cpp
  src/runtime_contract/workspace_store_loader.cpp
  src/runtime/concurrency_controller.cpp
  src/scheduler/thread_pool.cpp
  src/scheduler/scheduler.cpp
)

target_include_directories(cf_pipeline_v2_core PUBLIC
  ${CF_CONTRACTS_INCLUDE}
  ${CMAKE_CURRENT_SOURCE_DIR}/src
)

target_link_libraries(cf_pipeline_v2_core PUBLIC cf_pipeline_v2_utils)

if(UNIX AND NOT APPLE)
  target_link_libraries(cf_pipeline_v2_core PUBLIC dl)
endif()

add_executable(cf_pipeline_v2 src/main.cpp)

target_link_libraries(cf_pipeline_v2 PRIVATE cf_pipeline_v2_core)

add_custom_command(TARGET cf_pipeline_v2 POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
          ${TYPE_REGISTRY_V0_SOURCE_PATH}
          $<TARGET_FILE_DIR:cf_pipeline_v2>/${TYPE_REGISTRY_V0_FILENAME}
)

# Tests
add_library(cf_pipeline_v2_test_plugin SHARED
  ${CMAKE_CURRENT_SOURCE_DIR}/tests/test_plugin.cpp
  ${GENERATED_DIR}/cf_test_signature_hashes.h
)

target_include_directories(cf_pipeline_v2_test_plugin PUBLIC
  ${CF_CONTRACTS_INCLUDE}
  ${CMAKE_CURRENT_SOURCE_DIR}/src
  ${GENERATED_DIR}
)

target_link_libraries(cf_pipeline_v2_test_plugin PUBLIC cf_pipeline_v2_utils)
target_compile_definitions(cf_pipeline_v2_test_plugin PRIVATE CF_STEP_ABI_EXPORTS)

set_target_properties(cf_pipeline_v2_test_plugin PROPERTIES
  RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests
  LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests
  ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests
)

add_executable(cf_pipeline_v2_tests tests/test_main.cpp)

target_include_directories(cf_pipeline_v2_tests PRIVATE
  ${CF_CONTRACTS_INCLUDE}
  ${CMAKE_CURRENT_SOURCE_DIR}/src
)

target_link_libraries(cf_pipeline_v2_tests PRIVATE cf_pipeline_v2_core)

add_custom_command(TARGET cf_pipeline_v2_tests POST_BUILD
  COMMAND ${CMAKE_COMMAND} -E copy_if_different
          ${TYPE_REGISTRY_V0_SOURCE_PATH}
          $<TARGET_FILE_DIR:cf_pipeline_v2_tests>/${TYPE_REGISTRY_V0_FILENAME}
)

if (BUILD_TESTING)
  add_test(
    NAME cf_pipeline_v2_tests
    COMMAND cf_pipeline_v2_tests
  )
  set_tests_properties(cf_pipeline_v2_tests PROPERTIES
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  )
endif()

install(CODE [[
  file(REMOVE
    "${CMAKE_INSTALL_PREFIX}/bin/cf_siggen.exe"
    "${CMAKE_INSTALL_PREFIX}/bin/cf_siggen"
  )
  file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}/examples")
]])
install(TARGETS cf_pipeline_v2 RUNTIME DESTINATION bin)
install(FILES ${TYPE_REGISTRY_V0_SOURCE_PATH} DESTINATION bin)
