cmake_minimum_required(VERSION 3.15)
project(s100p_stage3_vlm CXX)

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

option(STAGE3_PROTOCOL_ONLY
       "Build only the host-testable protocol and service components" OFF)
option(BUILD_TESTING "Build development tests (requires the full source tree)" OFF)
option(BUILD_TOOLS "Build development fixtures and gates (requires the full source tree)" OFF)

if(BUILD_TESTING AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/vlm_protocol_test.cpp")
  message(FATAL_ERROR "BUILD_TESTING requires the development tests/ directory; release packages omit it")
endif()
if(BUILD_TOOLS AND (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/vision_prepare_fixture.cpp"
                   OR NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tools/prepare_equivalence_gate.cpp"))
  message(FATAL_ERROR "BUILD_TOOLS requires development tests/ and tools/ directories; release packages omit them")
endif()

function(stage3_strict target)
  if(MSVC)
    target_compile_options(${target} PRIVATE /W4 /WX)
  else()
    target_compile_options(${target} PRIVATE -Wall -Wextra -Werror)
  endif()
endfunction()

find_package(nlohmann_json REQUIRED)
find_package(Threads REQUIRED)
find_package(OpenSSL REQUIRED)

add_library(stage3_protocol STATIC src/vlm_protocol.cpp src/vision_preparation.cpp)
target_include_directories(stage3_protocol PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc)
target_link_libraries(stage3_protocol PUBLIC nlohmann_json::nlohmann_json OpenSSL::Crypto Threads::Threads)
stage3_strict(stage3_protocol)

add_library(stage3_vlm_service STATIC src/vlm_service.cpp)
target_include_directories(stage3_vlm_service PUBLIC
  ${CMAKE_CURRENT_SOURCE_DIR}/inc)
target_link_libraries(stage3_vlm_service PUBLIC stage3_protocol Threads::Threads)
stage3_strict(stage3_vlm_service)

add_library(stage3_http STATIC src/vlm_http.cpp)
target_include_directories(stage3_http PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc)
target_link_libraries(stage3_http PUBLIC stage3_vlm_service)
stage3_strict(stage3_http)

if(UNIX)
  add_library(stage3_http_server_io STATIC src/vlm_web_server.cpp)
  target_compile_definitions(stage3_http_server_io PRIVATE
    STAGE3_HTTP_SERVER_NO_MAIN)
  target_include_directories(stage3_http_server_io PUBLIC
    ${CMAKE_CURRENT_SOURCE_DIR}/inc)
  target_link_libraries(stage3_http_server_io PUBLIC stage3_http)
  stage3_strict(stage3_http_server_io)
  if(BUILD_TOOLS)
  add_executable(vision_prepare_fixture tests/vision_prepare_fixture.cpp)
  target_link_libraries(vision_prepare_fixture PRIVATE stage3_http stage3_gemma4_backend stage3_http_server_io)
  stage3_strict(vision_prepare_fixture)
  endif()
endif()

add_library(stage3_gemma4_backend STATIC src/gemma4_backend.cpp)
target_include_directories(stage3_gemma4_backend PUBLIC
  ${CMAKE_CURRENT_SOURCE_DIR}/inc)
target_link_libraries(stage3_gemma4_backend PUBLIC stage3_vlm_service)
stage3_strict(stage3_gemma4_backend)

if(BUILD_TESTING)
enable_testing()
if(UNIX)
  add_executable(vision_preparation_test tests/vision_preparation_test.cpp)
  target_link_libraries(vision_preparation_test PRIVATE stage3_http stage3_gemma4_backend)
  stage3_strict(vision_preparation_test)
  add_test(NAME vision_preparation_test COMMAND vision_preparation_test)
endif()
if(UNIX)
  add_executable(vlm_control_test tests/vlm_control_test.cpp)
  target_link_libraries(vlm_control_test PRIVATE stage3_http stage3_gemma4_backend stage3_http_server_io)
  stage3_strict(vlm_control_test)
  add_test(NAME vlm_control_test COMMAND vlm_control_test)
endif()
add_executable(vlm_protocol_test tests/vlm_protocol_test.cpp)
target_link_libraries(vlm_protocol_test PRIVATE stage3_protocol)
stage3_strict(vlm_protocol_test)
add_test(NAME vlm_protocol_test COMMAND vlm_protocol_test)

add_executable(vlm_service_test tests/vlm_service_test.cpp)
target_link_libraries(vlm_service_test PRIVATE stage3_vlm_service)
stage3_strict(vlm_service_test)
add_test(NAME vlm_service_test COMMAND vlm_service_test)

add_executable(gemma4_backend_test tests/gemma4_backend_test.cpp)
target_link_libraries(gemma4_backend_test PRIVATE stage3_gemma4_backend)
stage3_strict(gemma4_backend_test)
add_test(NAME gemma4_backend_test COMMAND gemma4_backend_test)

add_executable(http_router_test tests/http_router_test.cpp)
target_link_libraries(http_router_test PRIVATE stage3_http)
if(UNIX)
  target_link_libraries(http_router_test PRIVATE stage3_http_server_io)
endif()
stage3_strict(http_router_test)
add_test(NAME http_router_test COMMAND http_router_test)

if(UNIX)
  find_program(BASH_EXECUTABLE bash REQUIRED)
  add_executable(private_images_test tests/private_images_test.cpp)
  target_link_libraries(private_images_test PRIVATE stage3_protocol)
  stage3_strict(private_images_test)
  add_test(NAME private_images_test COMMAND private_images_test)
  add_test(NAME server_scripts_test
    COMMAND ${BASH_EXECUTABLE}
      ${CMAKE_CURRENT_SOURCE_DIR}/tests/server_scripts_test.sh
      ${CMAKE_CURRENT_SOURCE_DIR}/scripts/start_server.sh
      ${CMAKE_CURRENT_SOURCE_DIR}/scripts/stop_server.sh)
endif()

endif() # BUILD_TESTING

if(NOT STAGE3_PROTOCOL_ONLY)
  set(GEMMA4_SAMPLE_ROOT
      ""
      CACHE PATH "Path to the pinned Model Zoo Gemma4-E2B sample")
  set(GEMMA4_RUNTIME_ROOT "${GEMMA4_SAMPLE_ROOT}/runtime/cpp"
      CACHE PATH "Path to the Gemma4 C++ runtime source")
  set(TOKENIZERS_CPP_ROOT "${GEMMA4_SAMPLE_ROOT}/third_party/tokenizers-cpp"
      CACHE PATH "Path to the installed tokenizers-cpp source")

  if(NOT EXISTS "${GEMMA4_RUNTIME_ROOT}/inc/gemma4_text_engine.hpp")
    message(FATAL_ERROR
      "Gemma4 runtime not found under ${GEMMA4_RUNTIME_ROOT}; use scripts/build_vlm.sh --sample-root <official-sample> --work-dir <build-directory>")
  endif()
  if(NOT EXISTS "${TOKENIZERS_CPP_ROOT}/CMakeLists.txt")
    message(FATAL_ERROR
      "tokenizers-cpp is missing; run the official installer first")
  endif()

  find_path(HOBOT_INCLUDE_DIR hobot/dnn/hb_dnn.h
    PATHS /usr/hobot/include /usr/include NO_DEFAULT_PATH)
  find_library(DNN_LIB dnn
    PATHS /usr/hobot/lib /usr/lib/aarch64-linux-gnu NO_DEFAULT_PATH)
  find_library(HBUCP_LIB hbucp
    PATHS /usr/hobot/lib /usr/lib/aarch64-linux-gnu NO_DEFAULT_PATH)
  if(NOT HOBOT_INCLUDE_DIR OR NOT DNN_LIB OR NOT HBUCP_LIB)
    message(FATAL_ERROR
      "Horizon DNN/HBUCP headers or libraries were not found under /usr/hobot")
  endif()

  find_package(OpenCV REQUIRED COMPONENTS core imgcodecs imgproc)
  find_package(gflags REQUIRED)
  add_subdirectory("${TOKENIZERS_CPP_ROOT}"
                   "${CMAKE_CURRENT_BINARY_DIR}/tokenizers-cpp")

  add_library(gemma4_runtime STATIC
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_native_tokenizer.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_tokenizer.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_embeddings.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_kv_cache.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_text_engine.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_vision_preprocess.cpp
    ${GEMMA4_RUNTIME_ROOT}/src/gemma4_vision_engine.cpp)
  target_compile_definitions(gemma4_runtime PUBLIC SOC_S100P)
  target_include_directories(gemma4_runtime PUBLIC
    ${HOBOT_INCLUDE_DIR}
    ${OpenCV_INCLUDE_DIRS}
    ${GEMMA4_RUNTIME_ROOT}/inc
    ${TOKENIZERS_CPP_ROOT}/include)
  target_link_libraries(gemma4_runtime PUBLIC
    ${DNN_LIB}
    ${HBUCP_LIB}
    ${OpenCV_LIBS}
    ${CMAKE_DL_LIBS}
    tokenizers_cpp
    nlohmann_json::nlohmann_json)

  target_compile_definitions(stage3_gemma4_backend PRIVATE
    STAGE3_WITH_GEMMA4_RUNTIME)
  target_link_libraries(stage3_gemma4_backend PRIVATE gemma4_runtime)

  add_executable(gemma4_vlm_web src/vlm_web_server.cpp)
  if(BUILD_TOOLS)
  add_executable(prepare_equivalence_gate tools/prepare_equivalence_gate.cpp)
  target_include_directories(prepare_equivalence_gate PRIVATE ${OpenCV_INCLUDE_DIRS})
  target_link_libraries(prepare_equivalence_gate PRIVATE stage3_gemma4_backend ${OpenCV_LIBS})
  stage3_strict(prepare_equivalence_gate)
  endif()
  target_link_libraries(gemma4_vlm_web PRIVATE
    stage3_http
    stage3_gemma4_backend
    gflags)
  stage3_strict(gemma4_vlm_web)

  set_target_properties(gemma4_vlm_web PROPERTIES
    BUILD_RPATH "/usr/hobot/lib" INSTALL_RPATH "/usr/hobot/lib")
endif()
