cmake_minimum_required(VERSION 3.10)

project(SDFProv)

option(BUILD_DEMOS "Build demonstration programs" ON)
option(SDFP_DEBUG "Enable SDFP debug logging" OFF)

set(SDF_STANDARD_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/src/common)
set(SDF_VENDOR_INCLUDE_DIRS)

if(DEFINED SDF_DIR AND NOT DEFINED SDF_INCLUDE_DIR)
    set(SDF_INCLUDE_DIR ${SDF_DIR}/include CACHE PATH "SDF vendor include directory")
endif()

if(DEFINED SDF_INCLUDE_DIR AND NOT "${SDF_INCLUDE_DIR}" STREQUAL "")
    if(NOT IS_DIRECTORY "${SDF_INCLUDE_DIR}")
        message(FATAL_ERROR "SDF_INCLUDE_DIR does not exist: ${SDF_INCLUDE_DIR}")
    endif()
    list(APPEND SDF_VENDOR_INCLUDE_DIRS ${SDF_INCLUDE_DIR})
endif()

if(NOT EXISTS "${SDF_STANDARD_INCLUDE_DIR}/sdf_types.h" OR
   NOT EXISTS "${SDF_STANDARD_INCLUDE_DIR}/sdf_err.h")
    message(FATAL_ERROR "Bundled SDF headers are missing under: ${SDF_STANDARD_INCLUDE_DIR}")
endif()

if(NOT DEFINED HITLS_DIR)
    message(FATAL_ERROR "HITLS_DIR must be defined.")
else()
    set(HITLS_INCLUDE_DIR ${HITLS_DIR}/include)
endif()

if(NOT DEFINED HITLS_LIB_DIR)
    set(HITLS_LIB_DIR ${HITLS_DIR}/lib)
endif()

# Source directory layout
set(SRC_DIR      ${CMAKE_SOURCE_DIR}/src)
set(DEMO_DIR     ${CMAKE_SOURCE_DIR}/demo)

find_library(HITLS_BSL_LIB libhitls_bsl.so
    PATHS ${HITLS_LIB_DIR} ${HITLS_DIR}/build
    REQUIRED
)

find_library(HITLS_CRYPTO_LIB libhitls_crypto.so
    PATHS ${HITLS_LIB_DIR} ${HITLS_DIR}/build
    REQUIRED
)

# Recursively collect all .c files under src/
file(GLOB_RECURSE SDFP_SOURCES ${SRC_DIR}/*.c)

add_library(${PROJECT_NAME} SHARED ${SDFP_SOURCES})

target_include_directories(${PROJECT_NAME} PRIVATE
    # Optional vendor SDF SDK headers override the bundled standard headers.
    ${SDF_VENDOR_INCLUDE_DIRS}
    # Public API headers
    ${CMAKE_SOURCE_DIR}/include
    # Maintained internal standard SDF interface headers
    ${SDF_STANDARD_INCLUDE_DIR}
    # Internal source subdirectories
    ${SRC_DIR}
    ${SRC_DIR}/common
    ${SRC_DIR}/sm2
    ${SRC_DIR}/rsa
    # openHiTLS BSL and Crypto public headers
    ${HITLS_INCLUDE_DIR}/bsl
    ${HITLS_DIR}/bsl/include
    ${HITLS_DIR}/bsl/err/include
    ${HITLS_INCLUDE_DIR}/crypto
    # SM2 / ECC internals (needed by sm2_keymgmt)
    ${HITLS_DIR}/crypto/sm2/include
    ${HITLS_DIR}/crypto/ecc/include
    # Build configuration macros (hitls_build.h)
    ${HITLS_DIR}/config/macro_config
)

target_compile_options(${PROJECT_NAME} PRIVATE
    -Wall
    -Wextra
    -Werror
)

# Define required macros for SM2 / BSL functionality
target_compile_definitions(${PROJECT_NAME} PRIVATE
    HITLS_CRYPTO_SM2=1
    HITLS_CRYPTO_SM2_CRYPT=1
    HITLS_CRYPTO_SM2_SIGN=1
    HITLS_BSL_PARAMS=1
    HITLS_CRYPTO_KEY_DECODE_CHAIN=1
    HITLS_NO_CONFIG_CHECK=1  # Disable config check to avoid HITLS_BSL_ERR being auto-defined
)

if(SDFP_DEBUG)
    target_compile_definitions(${PROJECT_NAME} PRIVATE SDFP_DEBUG=1)
endif()

target_link_libraries(${PROJECT_NAME} PRIVATE
    ${HITLS_BSL_LIB}
    ${HITLS_CRYPTO_LIB}
    dl
)

# Only export CRYPT_EAL_ProviderInit; hide all other symbols
target_link_options(${PROJECT_NAME} PRIVATE
    -Wl,--version-script=${SRC_DIR}/common/version.lds
)

# ---- Demo programs ----
if(BUILD_DEMOS)
    find_library(HITLS_BSL_SO libhitls_bsl.so
        PATHS ${HITLS_LIB_DIR} ${HITLS_DIR}/build
        REQUIRED
    )

    set(DEMO_INCLUDE_DIRS
        ${SDF_VENDOR_INCLUDE_DIRS}
        ${CMAKE_SOURCE_DIR}/include
        ${SDF_STANDARD_INCLUDE_DIR}
        ${SRC_DIR}
        ${SRC_DIR}/common
        ${DEMO_DIR}
        ${HITLS_INCLUDE_DIR}/bsl
        ${HITLS_DIR}/bsl/include
        ${HITLS_INCLUDE_DIR}/crypto
    )
    set(DEMO_LINK_LIBS
        ${HITLS_CRYPTO_LIB}
        ${HITLS_BSL_SO}
        pthread
        dl
    )
    set(DEMO_COMPILE_OPTS -Wall -Wextra -Werror)

    # ---- Consolidated test runner ----
    # sdfp_demo.c is main()-only; test implementations live in separate files.
    add_executable(sdfp_demo
        ${DEMO_DIR}/sdfp_demo.c
        ${DEMO_DIR}/provider_init.c
        ${DEMO_DIR}/sm3_hash.c
        ${DEMO_DIR}/sm2_encrypt.c
        ${DEMO_DIR}/sm2_sign.c
        ${DEMO_DIR}/test_sm2_internal.c
        ${DEMO_DIR}/test_sm2_enc_internal.c
        ${DEMO_DIR}/sm4_test.c
        ${DEMO_DIR}/sm4_gcm.c
    )
    target_include_directories(sdfp_demo PRIVATE ${DEMO_INCLUDE_DIRS})
    target_compile_options(sdfp_demo PRIVATE ${DEMO_COMPILE_OPTS})
    target_link_libraries(sdfp_demo PRIVATE ${DEMO_LINK_LIBS})
    add_test(NAME sdfp_demo COMMAND sdfp_demo)
endif()

enable_testing()