cmake_minimum_required(VERSION 3.28)
cmake_policy(SET CMP0167 NEW)  # Suppress FindBoost removal warning

# ── CUDA is optional (not available on macOS) ───────────────────
include(CheckLanguage)
check_language(CUDA)
if(CMAKE_CUDA_COMPILER)
    project(ANSCORE LANGUAGES C CXX CUDA)
    set(ANSCORE_HAS_CUDA ON)
    set(CMAKE_CUDA_STANDARD 20)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
    set(CMAKE_CUDA_ARCHITECTURES 75 80 86 87 88 89 90 100)
    if(MSVC)
        set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --use-fast-math -Xcompiler=/utf-8")
    else()
        set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} --use-fast-math")
    endif()
else()
    project(ANSCORE LANGUAGES C CXX)
    set(ANSCORE_HAS_CUDA OFF)
    message(WARNING "CUDA not found — GPU-accelerated modules will be limited")
endif()

# ── Platform detection ──────────────────────────────────────────
if(WIN32)
    set(ANSCORE_PLATFORM "windows")
elseif(APPLE)
    set(ANSCORE_PLATFORM "macos")
else()
    set(ANSCORE_PLATFORM "linux")
endif()
message(STATUS "ANSCORE platform: ${ANSCORE_PLATFORM}, CUDA: ${ANSCORE_HAS_CUDA}")

# ── Global Settings ──────────────────────────────────────────────
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Output all binaries to a single directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)

# ── Compiler Configuration ──────────────────────────────────────
if(MSVC)
    # Dynamic CRT (/MD) — matches original VS projects and prebuilt libs like HWiNFO
    set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")

    # Apply MSVC flags only to C/C++ (not CUDA — nvcc doesn't understand them)
    add_compile_options(
        "$<$<COMPILE_LANGUAGE:C,CXX>:/W3>"
        "$<$<COMPILE_LANGUAGE:C,CXX>:/utf-8>"
        "$<$<AND:$<COMPILE_LANGUAGE:C,CXX>,$<NOT:$<CONFIG:MINSIZEREL>>>:/Zi>"
        # RelWithDebInfo: keep /O2 but disable inlining so debuggers can land
        # breakpoints on small dispatch functions (e.g. avframeToCVMat).
        "$<$<AND:$<COMPILE_LANGUAGE:C,CXX>,$<CONFIG:RelWithDebInfo>>:/Ob0>"
    )
    add_link_options(
        "$<$<NOT:$<CONFIG:DEBUG>>:/DEBUG:FULL>"
        # /OPT:REF and /OPT:ICF improve Release size/perf but confuse the
        # debugger (folds identical functions, strips unused ones). Apply
        # them to Release only, not RelWithDebInfo.
        "$<$<CONFIG:Release>:/OPT:REF>"
        "$<$<CONFIG:Release>:/OPT:ICF>"
        "$<$<CONFIG:RelWithDebInfo>:/OPT:NOREF>"
        "$<$<CONFIG:RelWithDebInfo>:/OPT:NOICF>"
    )
    add_compile_definitions(_CRT_SECURE_NO_WARNINGS _WINSOCK_DEPRECATED_NO_WARNINGS)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
    add_compile_options(-Wall -Wextra -Wno-unused-parameter)
    if(NOT APPLE)
        add_link_options(-Wl,--as-needed)
    endif()
endif()

# ── DebugView logging toggle (runtime-gated) ────────────────────
# ANS_DBG is compiled into every build by default and gated at runtime by
# ANSCENTER_IsDebugViewEnabled() (see ANSLicense.h/.cpp). Users toggle
# logging without a rebuild by creating or deleting
#   C:\ProgramData\ANSCENTER\ansvisdebugview.txt   (Windows), or
#   /tmp/ansvisdebugview.txt                       (POSIX),
# or by setting env var ANSCENTER_DBGVIEW=1/0. Effect propagates within ~2 s.
#
# This CMake option is a HARD KILL-SWITCH only — set it ON to strip ANS_DBG
# to ((void)0) at compile time. Use it only when even the cached atomic-load
# cost is unacceptable (tight inner loops). Default OFF = runtime-gated.
#
# Usage:
#   cmake -B build                                  # default: runtime-gated
#   cmake -B build -DANSCORE_DEBUGVIEW_STRIP=ON     # hard-strip all ANS_DBG
option(ANSCORE_DEBUGVIEW_STRIP "Hard-strip ANS_DBG calls at compile time (removes runtime toggle)" OFF)
if(ANSCORE_DEBUGVIEW_STRIP)
    add_compile_definitions(ANSCORE_DEBUGVIEW=0)
    message(STATUS "ANSCORE_DEBUGVIEW_STRIP = ON  — ANS_DBG compiled OUT (no runtime toggle)")
else()
    message(STATUS "ANSCORE_DEBUGVIEW_STRIP = OFF — ANS_DBG compiled IN, gated at runtime (sentinel file / env var)")
endif()

# ── Vendored libyuv (submodule: 3rdparty/libyuv) ────────────────
# SIMD-optimized YUV conversion library. Only genuinely fast on toolchains
# that understand GCC inline assembly (Clang/clang-cl/GCC) — 144 of its
# SIMD row functions live in row_gcc.cc. MSVC (cl.exe) can only compile the
# 8 routines in row_win.cc, so on MSVC libyuv silently falls back to the
# scalar C code in row_common.cc and runs ~10× slower than OpenCV+IPP's
# cv::cvtColor(COLOR_YUV2BGR_I420). Do NOT enable on MSVC builds.
#
# Default: OFF. Enable with `-DANSCORE_USE_LIBYUV=ON` only after switching
# the project's compiler to clang-cl / clang / gcc.
option(ANSCORE_USE_LIBYUV "Use libyuv for YUV→BGR conversion (only effective on Clang/GCC, NOT MSVC)" OFF)
# Prebuilt libyuv path — built separately with clang-cl so its SIMD rows compile,
# then linked into the MSVC main build (clang-cl output is MSVC-ABI-compatible).
# Override with -DANSCORE_LIBYUV_LIB=<path> if the .lib lives elsewhere.
set(ANSCORE_LIBYUV_LIB "${CMAKE_SOURCE_DIR}/3rdparty/libyuv/build-clangcl/Release/yuv.lib"
    CACHE FILEPATH "Path to the prebuilt libyuv static library (built with clang-cl)")

if(ANSCORE_USE_LIBYUV AND EXISTS "${ANSCORE_LIBYUV_LIB}")
    add_library(yuv STATIC IMPORTED GLOBAL)
    set_target_properties(yuv PROPERTIES
        IMPORTED_LOCATION "${ANSCORE_LIBYUV_LIB}"
        INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/libyuv/include")
    set(ANSCORE_HAS_LIBYUV ON)
    message(STATUS "libyuv: ENABLED (prebuilt static lib at ${ANSCORE_LIBYUV_LIB})")
elseif(ANSCORE_USE_LIBYUV)
    set(ANSCORE_HAS_LIBYUV OFF)
    message(WARNING "ANSCORE_USE_LIBYUV=ON but prebuilt libyuv not found at "
                    "${ANSCORE_LIBYUV_LIB}. Build it first with clang-cl:\n"
                    "  cmake -S 3rdparty/libyuv -B 3rdparty/libyuv/build-clangcl "
                    "-G \"Visual Studio 17 2022\" -T ClangCL -A x64\n"
                    "  cmake --build 3rdparty/libyuv/build-clangcl --config Release\n"
                    "Falling back to cv::cvtColor path.")
else()
    set(ANSCORE_HAS_LIBYUV OFF)
    message(STATUS "libyuv: DISABLED — using cv::cvtColor+IPP path (fast on MSVC)")
endif()

# ── External Dependencies ───────────────────────────────────────
include(cmake/Dependencies.cmake)

# ── Subprojects (ordered by dependency) ─────────────────────────

# Core — licensing & infrastructure
add_subdirectory(core/anslicensing)
add_subdirectory(core/ANSLicensingSystem)
add_subdirectory(core/ANSLibsLoader)

# Modules — feature DLLs (cross-platform)
add_subdirectory(modules/ANSMOT)
add_subdirectory(modules/ANSUtilities)
add_subdirectory(modules/ANSTrainingEngine)
add_subdirectory(modules/ANSLLM)

# Integrations — hardware & protocol DLLs
if(WIN32)
    add_subdirectory(integrations/ANNHUB)
    add_subdirectory(integrations/ANSIO)
    add_subdirectory(integrations/ANSONVIF)
endif()
add_subdirectory(integrations/ANSPulsar)
add_subdirectory(integrations/ANSRabbitMQ)

# Modules — engine layer (CUDA + inference frameworks)
if(ANSCORE_HAS_CUDA)
    add_subdirectory(modules/ANSODEngine)
    add_subdirectory(modules/ANSOCR)
    add_subdirectory(modules/ANSFR)
    add_subdirectory(modules/ANSLPR)
endif()
add_subdirectory(modules/ANSCV)

# Facade
add_subdirectory(ANSLIB)

# Tests
add_subdirectory(tests)
