# =============================================================================
# 项目名称: HyperLPR3-LinuxAPP
# 功能: 车牌识别应用程序
# 优化目标: 减小可执行文件体积、提升编译效率、增强可移植性
# =============================================================================

# -----------------------------------------------------------------------------
# 1. CMake 最低版本要求
# 说明: 3.10.2 是 Ubuntu 18.04 默认版本，如需使用新特性可提高到 3.16+
# -----------------------------------------------------------------------------
#cmake_minimum_required(VERSION 3.10.2)
#cmake_minimum_required(VERSION 3.16.2)
#cmake_minimum_required(VERSION 3.28)
#当前CMake 3.25.1

cmake_minimum_required(VERSION 3.25.1)

# -----------------------------------------------------------------------------
# 2. 项目定义
# -----------------------------------------------------------------------------
project(HyperLPR3-LinuxAPP
    VERSION 1.0.0
    DESCRIPTION "HyperLPR3 车牌识别 Linux 应用"
    LANGUAGES CXX C
)

# -----------------------------------------------------------------------------
# 3. C++ 标准设置
# 说明: 使用 C++17 标准，启用标准强制检查
# -----------------------------------------------------------------------------
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)  # 强制要求编译器支持 C++17，不支持则报错
set(CMAKE_CXX_EXTENSIONS OFF)        # 禁用编译器扩展（如 GNU++17），确保跨平台兼容

# -----------------------------------------------------------------------------
# 4. 构建类型设置
# 说明: 
#   - Release: 发布模式，启用优化，去除调试信息，体积最小
#   - Debug:   调试模式，保留调试信息，便于开发调试
#   - RelWithDebInfo: 带调试信息的发布模式
#   - MinSizeRel: 最小体积发布模式（比 Release 更激进优化体积）
# -----------------------------------------------------------------------------
if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

# 设置可选的构建类型（供 cmake-gui 或 ccmake 使用）
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS 
    "Debug" "Release" "MinSizeRel" "RelWithDebInfo")

# -----------------------------------------------------------------------------
# 5. 编译器优化标志（Release 模式专用）
# 说明: 这些标志专门用于减小编译后的可执行文件体积
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
    # -O3: 最高级别优化（速度优先）
    # -Os: 优化代码大小（体积优先，推荐用于嵌入式）
    # -s:  去除符号表信息（strip）
    # -fvisibility=hidden: 隐藏符号，减少导出表大小
    # -fvisibility-inlines-hidden: 隐藏内联函数符号
    # -ffunction-sections -fdata-sections: 为每个函数/数据创建独立段
    # -Wl,--gc-sections: 链接时删除未使用的段
    # -Wl,--strip-all: 链接时去除所有符号
    # -flto: 链接时优化（Link Time Optimization），可显著减小体积

    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -s")
    set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -s")

    # 可选: 启用 LTO（链接时优化）- 需要编译器支持，可减小 10-30% 体积
    # 注意: 会增加编译时间，某些编译器可能有兼容性问题
    # set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)

    # 可选: 最小体积模式（比 Release 更激进）
    # set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -s -fvisibility=hidden -fvisibility-inlines-hidden")
endif()

# -----------------------------------------------------------------------------
# 6. 优先使用动态链接库（减小可执行文件体积的关键）
# 说明: 
#   - ON:  优先查找动态库（.so），体积最小，但部署时需确保目标机有对应库
#   - OFF: 优先查找静态库（.a），体积大但独立性强
# 建议: 开发/测试用动态库，发布时根据部署环境决定
# -----------------------------------------------------------------------------
option(USE_STATIC_LIBS "使用静态库链接（体积大但独立性强）" OFF)

if(NOT USE_STATIC_LIBS)
    set(BUILD_SHARED_LIBS ON)
    # 设置动态库查找优先级
    set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".so.1" ".so.0" ".a")
else()
    set(BUILD_SHARED_LIBS OFF)
    set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so")
endif()

# -----------------------------------------------------------------------------
# 7. 查找 PkgConfig 模块
# 说明: pkg-config 用于自动查找系统安装的库的头文件和链接参数
# -----------------------------------------------------------------------------
find_package(PkgConfig REQUIRED)

# -----------------------------------------------------------------------------
# 8. 查找第三方库
# -----------------------------------------------------------------------------

# 8.1 FreeType2 - 字体渲染库
# 用途: 在图像上绘制中文字符
pkg_check_modules(FREETYPE REQUIRED freetype2)

# 8.2 SQLite3 - 轻量级数据库
# 用途: 存储车牌识别记录
pkg_check_modules(SQLITE3 REQUIRED sqlite3)

# 8.3 cURL - HTTP 客户端库
# 用途: 网络请求（如上传识别结果到服务器）
find_package(CURL REQUIRED)

# 8.4 OpenCV - 计算机视觉库（体积大户！）
# 说明: 如果只需要核心模块，可以指定 COMPONENTS 减少依赖
# 例如: find_package(OpenCV REQUIRED COMPONENTS core imgproc imgcodecs highgui)
find_package(OpenCV REQUIRED)

# 8.5 OpenSSL - 加密/SSL 库
# 用途: HTTPS 请求、数据加密
find_package(OpenSSL REQUIRED)

# 8.6 FFmpeg - 视频解码库（v43新增）
# 用途: RTSP流解码，HEVC DRM硬件解码，H.264软解
pkg_check_modules(AVFORMAT REQUIRED libavformat)
pkg_check_modules(AVCODEC REQUIRED libavcodec)
pkg_check_modules(AVUTIL REQUIRED libavutil)
pkg_check_modules(SWSCALE REQUIRED libswscale)

# 8.7 libcrypt - 密码哈希库（fix24 auth系统新增）
# 用途: bcrypt 密码哈希（通过系统 libcrypt 的 crypt_r）
find_library(CRYPT_LIBRARY crypt
    PATHS
        /usr/lib
        /usr/lib/aarch64-linux-gnu
        /usr/lib/x86_64-linux-gnu
        /usr/local/lib
    DOC "libcrypt path"
)
if(NOT CRYPT_LIBRARY)
    message(WARNING "libcrypt not found, auth system will not work. Install libcrypt-dev.")
else()
    message(STATUS "Found libcrypt: ${CRYPT_LIBRARY}")
endif()

# -----------------------------------------------------------------------------
# 9. 查找 cJSON 库
# 说明: cJSON 可能没有 .pc 文件，使用多种方式查找
# -----------------------------------------------------------------------------

# 方法1: 尝试使用 pkg-config 查找（某些系统可能安装了 cjson.pc）
pkg_check_modules(CJSON cjson)

if(CJSON_FOUND)
    # 使用 pkg-config 找到的结果
    message(STATUS "通过 pkg-config 找到 cJSON")
    set(CJSON_LIBRARY ${CJSON_LIBRARIES})
    set(CJSON_INCLUDE_DIR ${CJSON_INCLUDE_DIRS})
else()
    # 方法2: 手动查找库文件
    message(STATUS "pkg-config 未找到 cJSON，尝试手动查找...")

    # 查找库文件（优先动态库）
    find_library(CJSON_LIBRARY 
        NAMES cjson
        PATHS 
            /usr/lib 
            /usr/lib/aarch64-linux-gnu 
            /usr/lib/x86_64-linux-gnu
            /usr/local/lib
            /opt/cjson/lib
        DOC "cJSON library path"
    )

    # 查找头文件
    find_path(CJSON_INCLUDE_DIR 
        NAMES cJSON.h
        PATHS 
            /usr/include 
            /usr/include/cjson
            /usr/local/include
            /usr/local/include/cjson
            /opt/cjson/include
        DOC "cJSON header path"
    )
endif()

# 检查是否找到 cJSON
if(NOT CJSON_LIBRARY)
    message(WARNING "未找到 cJSON 库，尝试使用默认路径...")
    # 尝试常见默认路径
    if(EXISTS "/usr/lib/aarch64-linux-gnu/libcjson.so")
        set(CJSON_LIBRARY "/usr/lib/aarch64-linux-gnu/libcjson.so")
    elseif(EXISTS "/usr/lib/x86_64-linux-gnu/libcjson.so")
        set(CJSON_LIBRARY "/usr/lib/x86_64-linux-gnu/libcjson.so")
    elseif(EXISTS "/usr/lib/libcjson.so")
        set(CJSON_LIBRARY "/usr/lib/libcjson.so")
    elseif(EXISTS "/usr/local/lib/libcjson.so")
        set(CJSON_LIBRARY "/usr/local/lib/libcjson.so")
    else()
        message(FATAL_ERROR "无法找到 cJSON 库！请安装: sudo apt install libcjson-dev")
    endif()
endif()

if(NOT CJSON_INCLUDE_DIR)
    # 如果找不到头文件目录，使用系统默认包含路径
    # 并假设头文件直接在 /usr/include 下
    if(EXISTS "/usr/include/cJSON.h")
        set(CJSON_INCLUDE_DIR "/usr/include")
    elseif(EXISTS "/usr/include/cjson/cJSON.h")
        set(CJSON_INCLUDE_DIR "/usr/include/cjson")
    else()
        message(WARNING "未找到 cJSON 头文件目录，使用系统默认路径")
        set(CJSON_INCLUDE_DIR "")  # 空表示使用系统默认路径
    endif()
endif()

# 验证找到的文件
message(STATUS "cJSON 库路径: ${CJSON_LIBRARY}")
message(STATUS "cJSON 头文件路径: ${CJSON_INCLUDE_DIR}")

if(NOT EXISTS ${CJSON_LIBRARY})
    message(FATAL_ERROR "cJSON 库文件不存在: ${CJSON_LIBRARY}")
endif()

# -----------------------------------------------------------------------------
# 10. HyperLPR3 SDK 设置
# 说明: 车牌识别核心库，可能包含大型模型数据
# -----------------------------------------------------------------------------
set(HYPERLPR3_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/hyperlpr3")
set(HYPERLPR3_INCLUDE_DIR "${HYPERLPR3_ROOT}/include")
set(HYPERLPR3_LIB_DIR "${HYPERLPR3_ROOT}/lib")

# 检查 SDK 是否存在
if(NOT EXISTS ${HYPERLPR3_INCLUDE_DIR})
    message(FATAL_ERROR "HyperLPR3 SDK 头文件目录不存在: ${HYPERLPR3_INCLUDE_DIR}")
endif()

if(NOT EXISTS ${HYPERLPR3_LIB_DIR})
    message(FATAL_ERROR "HyperLPR3 SDK 库目录不存在: ${HYPERLPR3_LIB_DIR}")
endif()

# 添加 SDK 库目录到链接器搜索路径
link_directories(${HYPERLPR3_LIB_DIR})

# -----------------------------------------------------------------------------
# 11. 包含目录设置
# 说明: 使用 target_include_directories 替代全局 include_directories（现代 CMake 推荐）
# -----------------------------------------------------------------------------

# 源文件列表
set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/common.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/config.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/rtsp_capture.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/plate_recognizer.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/station_lock.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/database.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/network_client.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/feishu_client.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/web_server.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/monitor.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/utils.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/weight_scale.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/weight_dispatcher.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/mqtt_client.cpp
    # ✅ fix24 功能一：登录认证系统
    ${CMAKE_CURRENT_SOURCE_DIR}/src/bcrypt/bcrypt.c
    ${CMAKE_CURRENT_SOURCE_DIR}/src/auth_crypto.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/auth_db.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/auth_session.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/auth_middleware.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/auth_api.cpp
    # fix24 v24: Web管理功能
    ${CMAKE_CURRENT_SOURCE_DIR}/src/system_monitor.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/frpc_manager.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/ssh_manager.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/log_manager.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/src/system_metrics_manager.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/cvxFont.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/md5ex1.c
    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/ini.c
)

# 创建可执行文件
add_executable(PlateRecApp ${SOURCES})

# 为目标设置包含目录（PRIVATE 表示仅本目标使用）
set(INCLUDE_DIRS
    ${PROJECT_SOURCE_DIR}/src                 # 模块头文件
    ${PROJECT_SOURCE_DIR}/third_party         # 第三方头文件
    ${PROJECT_SOURCE_DIR}                    # 项目根目录
    ${HYPERLPR3_INCLUDE_DIR}                   # HyperLPR3 SDK 头文件
    ${OpenCV_INCLUDE_DIRS}                     # OpenCV 头文件
    ${FREETYPE_INCLUDE_DIRS}                   # FreeType 头文件
    ${SQLITE3_INCLUDE_DIRS}                    # SQLite3 头文件
    ${AVFORMAT_INCLUDE_DIRS}                   # FFmpeg libavformat 头文件（v43新增）
    ${AVCODEC_INCLUDE_DIRS}                    # FFmpeg libavcodec 头文件（v43新增）
    ${AVUTIL_INCLUDE_DIRS}                     # FFmpeg libavutil 头文件（v43新增）
    ${SWSCALE_INCLUDE_DIRS}                    # FFmpeg libswscale 头文件（v43新增）
)

# 只有当找到有效的 cJSON 头文件目录时才添加
if(CJSON_INCLUDE_DIR AND NOT CJSON_INCLUDE_DIR STREQUAL "")
    list(APPEND INCLUDE_DIRS ${CJSON_INCLUDE_DIR})
endif()

target_include_directories(PlateRecApp PRIVATE ${INCLUDE_DIRS})

# -----------------------------------------------------------------------------
# 12. 链接库设置
# 说明: 链接顺序很重要！被依赖的库放在后面
# 顺序原则: 目标 <- 直接依赖 <- 间接依赖 <- 系统库
# -----------------------------------------------------------------------------
target_link_libraries(PlateRecApp PRIVATE
    # 1. HyperLPR3 SDK（车牌识别核心，可能包含模型数据）
    hyperlpr3

    # 2. 数据库和配置库
    ${SQLITE3_LIBRARIES}    # SQLite3

    # 3. 图像/字体处理库
    ${FREETYPE_LIBRARIES}   # FreeType2（字体渲染）
    ${OpenCV_LIBS}          # OpenCV（计算机视觉，体积较大）

    # 4. 网络/加密库
    CURL::libcurl           # cURL（HTTP 客户端）
    ${OPENSSL_LIBRARIES}    # OpenSSL（加密/HTTPS）
    mosquittopp             # MQTT C++客户端（fix20新增）
    mosquitto               # MQTT C库（fix20新增）
    ${CRYPT_LIBRARY}        # libcrypt（密码哈希，fix24 auth系统新增）

    # 5. 数据格式库
    ${CJSON_LIBRARY}        # cJSON（JSON 解析）

    # 6. FFmpeg 视频解码库（v43新增）
    ${AVFORMAT_LIBRARIES}   # libavformat（容器解封装）
    ${AVCODEC_LIBRARIES}    # libavcodec（视频解码，含DRM硬解）
    ${AVUTIL_LIBRARIES}     # libavutil（工具函数）
    ${SWSCALE_LIBRARIES}    # libswscale（像素格式转换）

    # 7. 系统线程库（通常自动链接，显式指定更安全）
    pthread

    # 8. 数学库（某些平台需要）
    m

    # 9. 实时库（某些平台需要）
    rt
)

# -----------------------------------------------------------------------------
# 13. 链接选项设置（体积优化）
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
    # --as-needed: 只链接实际使用的符号（避免过度链接）
    # --gc-sections: 删除未使用的段
    # -O1: 链接时优化级别
    target_link_options(PlateRecApp PRIVATE
        "LINKER:--as-needed"
        "LINKER:--gc-sections"
    )
endif()

# -----------------------------------------------------------------------------
# 14. 编译后处理（Release 模式）
# 说明: 使用 strip 去除符号表，进一步减小体积
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Release")
    add_custom_command(TARGET PlateRecApp POST_BUILD
        COMMAND ${CMAKE_STRIP} $<TARGET_FILE:PlateRecApp>
        COMMENT "去除符号表以减小程序体积..."
    )
endif()

# -----------------------------------------------------------------------------
# 15. 安装规则（可选）
# 说明: 定义 make install 时的安装路径
# -----------------------------------------------------------------------------
install(TARGETS PlateRecApp
    RUNTIME DESTINATION bin          # 可执行文件
    LIBRARY DESTINATION lib            # 动态库
    ARCHIVE DESTINATION lib/static     # 静态库
)

# -----------------------------------------------------------------------------
# 16. 输出配置信息（便于调试）
# -----------------------------------------------------------------------------
message(STATUS "========================================")
message(STATUS "项目配置信息:")
message(STATUS "  项目名称: ${PROJECT_NAME}")
message(STATUS "  项目版本: ${PROJECT_VERSION}")
message(STATUS "  C++ 标准: C++${CMAKE_CXX_STANDARD}")
message(STATUS "  构建类型: ${CMAKE_BUILD_TYPE}")
message(STATUS "  使用静态库: ${USE_STATIC_LIBS}")
message(STATUS "----------------------------------------")
message(STATUS "库路径信息:")
message(STATUS "  OpenCV: ${OpenCV_INCLUDE_DIRS}")
message(STATUS "  OpenCV 库: ${OpenCV_LIBS}")
message(STATUS "  HyperLPR3: ${HYPERLPR3_INCLUDE_DIR}")
message(STATUS "  cJSON 库: ${CJSON_LIBRARY}")
message(STATUS "  cJSON 头文件: ${CJSON_INCLUDE_DIR}")
message(STATUS "  libcrypt: ${CRYPT_LIBRARY}")
message(STATUS "========================================")

# -----------------------------------------------------------------------------
# 17. 体积优化建议（构建时提示）
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Release" AND NOT USE_STATIC_LIBS)
    message(STATUS "")
    message(STATUS "【体积优化提示】")
    message(STATUS "  1. 当前使用动态链接，确保目标机安装以下库:")
    message(STATUS "     - OpenCV: libopencv-core, libopencv-imgproc, ...")
    message(STATUS "     - OpenSSL: libssl, libcrypto")
    message(STATUS "     - SQLite3: libsqlite3")
    message(STATUS "     - cJSON: libcjson")
    message(STATUS "     - FreeType2: libfreetype")
    message(STATUS "     - cURL: libcurl")
    message(STATUS "     - libcrypt: libcrypt (密码哈希)")
    message(STATUS "")
    message(STATUS "  2. 如需静态链接（独立运行但体积大）:")
    message(STATUS "     cmake -DUSE_STATIC_LIBS=ON ..")
    message(STATUS "")
    message(STATUS "  3. 如需进一步减小体积，启用 LTO:")
    message(STATUS "     取消注释第 56 行的 set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)")
    message(STATUS "")
endif()
