cmake_minimum_required(VERSION 3.20)

get_filename_component(MY_PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
project(${MY_PROJECT_NAME} C ASM)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

# ==============================================================================
# 🎯 宏：add_project_modules_with_tests
# ==============================================================================
macro(add_project_modules_with_tests OUT_APP_SOURCES OUT_TEST_FILES_LIST)
    foreach(MODULE_DIR ${ARGN})
        if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}")
            message(STATUS "[Module Found]: ${MODULE_DIR}")

            # 自动将该目录加入全局头文件包含路径
            include_directories("${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}")

            # 1. 搜集该目录下所有的 C/C++ 源文件
            file(GLOB ALL_MODULE_FILES
                    "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}/*.cpp"
                    "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}/*.cc"
                    "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}/*.c"
                    "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}/*.s"
                    "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_DIR}/*.S"
            )

            # 2. 分离出测试文件 (*.t.cpp 或 *.t.c)
            foreach(FILE_PATH ${ALL_MODULE_FILES})
                # 匹配以 .t.cpp, .t.cc, .t.c 结尾的文件
                if(FILE_PATH MATCHES "\\.t\\.(cpp|cc|c)$")
                    list(APPEND ${OUT_TEST_FILES_LIST} ${FILE_PATH})
                    message("\tTestUnit: ${FILE_PATH}")
                else()
                    # 剩下的才是主程序的源代码
                    list(APPEND ${OUT_APP_SOURCES} ${FILE_PATH})
                    message("\tSource: ${FILE_PATH}")
                endif()
            endforeach()

        else()
            message(WARNING "[Module Warning]: Directory '${MODULE_DIR}' does not exist!")
        endif()
    endforeach()
endmacro()

# ==============================================================================
# 🚀 使用宏收集目标目录
# ==============================================================================
# 初始化一个空变量用于存放所有源码
set(SOURCES "")
set(TEST_SOURCES "")

configure_file(c_Config.h.in c_Config.h @ONLY)

# 调用宏：第一个参数是接收源码的变量，后面跟上您所有的子目录
add_project_modules_with_tests(SOURCES TEST_SOURCES
        Base
        Foundation
        Graph
        Math
        Memory
        Search
        Sort
        String
        Context
)

#foreach (item ${SOURCES})
#    message(STATUS "[${MY_PROJECT_NAME}] SOURCE: ${item}")
#endforeach ()
add_library(${MY_PROJECT_NAME} ${SOURCES})
target_include_directories(${MY_PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
if(WIN32)
    target_link_libraries(${MY_PROJECT_NAME} PUBLIC ws2_32)
endif()

# ==============================================================================
# 🧪 自动生成并注册单元测试
# ==============================================================================
foreach(TEST_FILE ${TEST_SOURCES})
    # 获取文件名（不含路径），例如 "C:/project/Math/matrix.t.cpp" -> "matrix.t.cpp"
    get_filename_component(TEST_NAME_WE ${TEST_FILE} NAME_WE)
    # 构造测试可执行文件的名称，例如 "test_matrix"
    set(TEST_EXE_NAME "test_${TEST_NAME_WE}")

    # 编译此测试程序：测试程序 = 测试源文件 + 主程序除main外的所有依赖
    # 注意：如果您的主程序包含 main.cpp，建议将 main.cpp 从 ${APP_SOURCES} 中剥离，
    # 或者在这里只链接需要的源文件，防止出现多个 main 函数冲突。
#    add_executable(${TEST_EXE_NAME} ${TEST_FILE} ${APP_SOURCES})
    add_executable(${TEST_EXE_NAME} ${TEST_FILE})
    target_link_libraries(${TEST_EXE_NAME} PRIVATE ${MY_PROJECT_NAME})

    # 将其注册到 CMake 的 ctest 测试集中
    add_test(NAME ${TEST_EXE_NAME} COMMAND ${TEST_EXE_NAME})

    message(STATUS "[Test Registered]: ${TEST_EXE_NAME}")
endforeach()
