#build_mqtt_demo.sh
#!/bin/bash
# mqtt_client_sdk 联合编译脚本（芯祥联科技 - MQTT Client协议栈）
# 功能：编译examples目录4个DEMO + 链接闭源库 + 宏开关控制
# 全平台支持：Linux/Windows/STM32/arm32/arm64/vs2022

# ==================== MinGW编码环境配置 ====================
if [[ "$(uname -s)" == *"MINGW"* ]]; then
    chcp 65001 >/dev/null 2>&1
    export LC_ALL=zh_CN.UTF-8
fi

# ==================== 【修复】关闭静默失败选项 ====================
# set -eo pipefail

# ==================== 启动提示 ====================
echo -e "\033[31m====================================\033[0m" >&2
echo -e "\033[31m[MQTT CLIENT SDK 编译] 启动中...\033[0m" >&2
echo -e "\033[31m====================================\033[0m" >&2
sleep 0.3

# ==================== 核心目录配置 ====================
OPEN_SRC_DIRS=(
    "./comm"
    "./os"
    "./network"
    "./examples"
    "./crypto"
)

INC_DIRS=(
    "./"
    "./comm"
    "./os"
    "./network"
    "./examples"
    "./client_core"
    "./protocol"
    "./lib"
    "./crypto"
)

SDK_LIB_ROOT="./lib"
OUTPUT_ROOT="./bin"
TARGET_BASE_NAME="xxl_mqtt_client"

# 交叉编译器配置
ARM32_CC="arm-linux-gnueabihf-gcc"
ARM64_CC="aarch64-linux-gnu-gcc"
STM32_CC="arm-none-eabi-gcc"
STM32_CPU="cortex-m4"
STM32_LINK_SCRIPT="./platform/stm32/linker.ld"
STM32_LD_FLAGS="-nostdlib -lc -lm -lnosys -Wl,--gc-sections"

# ==================== 宏开关配置 ====================
MQTT_ENABLE_50="1"
MQTT_CRYPTO_ENABLE="1"

CLIENT_CMD_DEMO="0"
CLIENT_AUTO_TEST="0"
CLIENT50_CMD_DEMO="0"
MQTT50_AOTUTEST_DEMO="0"

# ==================== 全局变量 ====================
CC=""
SDK_LIB_FILE=""
TARGET_NAME=""
BUILD_PLATFORM="all"
DEBUG_MODE=0
OPT_FLAGS="-O2"
ERROR_LOG="./compile_error.log"
SCRIPT_DIR=$(cd "$(dirname "$0")" || exit 1; pwd)

# ==================== 工具函数 ====================
show_help() {
    echo -e "\033[32m==== MQTT 编译脚本 ====\033[0m" >&2
    echo "用法：$0 [-p|--platform <平台>] [-d|--debug] [-demo <cmd|auto|50cmd|50auto>] [-v <311|50>] [-h|--help]" >&2
    echo "支持：linux windows stm32 arm32 arm64 vs2022 all" >&2
    echo "  -d, --debug       开启调试模式：-O0 -g -ggdb3（默认：-O2 发行模式）" >&2
    echo "  -demo             选择DEMO：cmd|auto|50cmd|50auto" >&2
    echo "  -v                MQTT版本：311|50" >&2
    echo "示例：$0 -p windows -demo cmd -v 311" >&2
    echo "示例：$0 -p vs2022 -demo 50auto -v 50" >&2
    exit 0
}

check_mqtt_dir() {
    echo -e "\033[32m[INFO] 校验目录结构...\033[0m" >&2
    local required_dirs=("comm" "os" "network" "examples" "lib" "crypto")
    for dir in "${required_dirs[@]}"; do
        if [[ ! -d "${SCRIPT_DIR}/${dir}" ]]; then
            echo -e "\033[31m[ERROR] 缺失目录：${SCRIPT_DIR}/${dir}\033[0m" >&2
            exit 1
        fi
    done
    echo -e "\033[32m[INFO] ✅ 目录校验通过\033[0m" >&2
}

check_deps() {
    local platform="$1"
    echo -e "\033[32m[INFO] 校验${platform}依赖...\033[0m" >&2

    if [[ "$platform" == "linux" || "$platform" == "windows" || "$platform" == "vs2022" ]]; then
        if ! command -v "gcc" &>/dev/null; then
            echo -e "\033[31m[ERROR] 未找到gcc编译器\033[0m" >&2
            exit 1
        fi
    fi

    if [[ "$platform" == "arm32" ]] && ! command -v "${ARM32_CC}" &>/dev/null; then
        echo -e "\033[31m[ERROR] 缺失arm32交叉编译器\033[0m" >&2
        exit 1
    fi
    if [[ "$platform" == "arm64" ]] && ! command -v "${ARM64_CC}" &>/dev/null; then
        echo -e "\033[31m[ERROR] 缺失arm64交叉编译器\033[0m" >&2
        exit 1
    fi
    if [[ "$platform" == "stm32" ]] && ! command -v "${STM32_CC}" &>/dev/null; then
        echo -e "\033[31m[ERROR] 缺失STM32交叉编译器\033[0m" >&2
        exit 1
    fi

    echo -e "\033[32m[INFO] ✅ 依赖校验通过\033[0m" >&2
}

parse_args() {
    echo -e "\033[32m[INFO] 解析编译参数...\033[0m" >&2
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -p|--platform)
                BUILD_PLATFORM="$2"
                shift 2
                ;;
            -d|--debug)
                DEBUG_MODE=1
                shift
                ;;
            -demo)
                DEMO_CHOICE="$2"
                shift 2
                ;;
            -v)
                MQTT_VER="$2"
                shift 2
                ;;
            -h|--help)
                show_help
                ;;
            *)
                echo -e "\033[31m[ERROR] 无效参数：$1\033[0m" >&2
                show_help
                ;;
        esac
    done

    # ------------- 版本选择 -------------
    if [ "$MQTT_VER" = "50" ]; then
        MQTT_ENABLE_50=1
    else
        MQTT_ENABLE_50=0
    fi

    # ------------- DEMO 选择 -------------
    CLIENT_CMD_DEMO=0
    CLIENT_AUTO_TEST=0
    CLIENT50_CMD_DEMO=0
    MQTT50_AOTUTEST_DEMO=0

    case "$DEMO_CHOICE" in
        cmd)      CLIENT_CMD_DEMO=1 ;;
        auto)     CLIENT_AUTO_TEST=1 ;;
        50cmd)    CLIENT50_CMD_DEMO=1 ;;
        50auto)   MQTT50_AOTUTEST_DEMO=1 ;;
    esac

    if [ "$DEBUG_MODE" -eq 1 ]; then
        OPT_FLAGS="-O0 -g -ggdb3"
    else
        OPT_FLAGS="-O2"
    fi

    local valid_platforms=("linux" "windows" "stm32" "arm32" "arm64" "vs2022" "all")
    if [[ ! " ${valid_platforms[@]} " =~ " ${BUILD_PLATFORM} " ]]; then
        echo -e "\033[31m[ERROR] 无效编译平台\033[0m" >&2
        exit 1
    fi
    echo -e "\033[32m[INFO] ✅ 目标平台：${BUILD_PLATFORM}\033[0m" >&2
}

auto_select_demo() {
    if [[ "${CLIENT_CMD_DEMO}" == "1" ]]; then
        DEMO_SUFFIX="_cmd_demo"
    elif [[ "${CLIENT_AUTO_TEST}" == "1" ]]; then
        DEMO_SUFFIX="_auto_test"
    elif [[ "${CLIENT50_CMD_DEMO}" == "1" ]]; then
        DEMO_SUFFIX="_50_cmd_demo"
    elif [[ "${MQTT50_AOTUTEST_DEMO}" == "1" ]]; then
        DEMO_SUFFIX="_50_autotest"
    else
        echo -e "\033[31m[ERROR] 必须开启一个DEMO宏\033[0m" >&2
        exit 1
    fi
}

init_platform() {
    local platform="$1"
    rm -f "${ERROR_LOG}"
    auto_select_demo
    echo -e "\033[32m[INFO] 初始化${platform}配置...\033[0m" >&2

    DEMO_DEFINES="-DCLIENT_CMD_DEMO=${CLIENT_CMD_DEMO} \
-DCLIENT_AUTO_TEST=${CLIENT_AUTO_TEST} \
-DCLIENT50_CMD_DEMO=${CLIENT50_CMD_DEMO} \
-DMQTT50_AOTUTEST_DEMO=${MQTT50_AOTUTEST_DEMO} \
-DMQTT_ENABLE_50=${MQTT_ENABLE_50} \
-DMQTT_CRYPTO_ENABLE=${MQTT_CRYPTO_ENABLE} \
-DXXL_LIC_ENABLE=1"

    common_flags="${OPT_FLAGS} -std=c99 ${DEMO_DEFINES} -Wall -Wno-error \
-Wno-unused-function -Wno-comment -Wno-stringop-truncation \
-Wno-implicit-function-declaration -Wno-int-conversion \
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -fno-stack-protector"

    case "${platform}" in
        linux)
            CC="gcc"
            dir_suffix="linux"
            lib_suffix="a"
            exe=""
            LDFLAGS="-lpthread -lrt"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            ;;
        windows)
            CC="gcc"
            dir_suffix="windows"
            lib_suffix="lib"
            exe=".exe"
            LDFLAGS="-lws2_32 -lbcrypt -mconsole -static-libgcc -static"
            CFLAGS="${common_flags} -DWIN32 -D_WIN32 -DXXL_MQTT_STATIC -DBUILD_MQTT_DLL=0 -Wno-comment -finput-charset=utf-8 -fexec-charset=utf-8"
            ;;
        stm32)
            CC="${STM32_CC}"
            dir_suffix="stm32"
            lib_suffix="a"
            exe=".elf"
            CFLAGS="${common_flags} -DSTM32 -mcpu=${STM32_CPU} -mthumb -ffunction-sections -fdata-sections"
            LDFLAGS="${STM32_LD_FLAGS}"
            ;;
        arm32)
            CC="${ARM32_CC}"
            dir_suffix="arm32"
            lib_suffix="a"
            exe=""
            LDFLAGS="-lpthread -lrt"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            ;;
        arm64)
            CC="${ARM64_CC}"
            dir_suffix="arm64"
            lib_suffix="a"
            exe=""
            LDFLAGS="-lpthread -lrt"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            ;;
        vs2022)
            CC="x86_64-w64-mingw32-gcc"
            dir_suffix="vs2022"
            lib_suffix="lib"
            exe=".exe"
            LDFLAGS="-lws2_32 -lbcrypt -mconsole -static-libgcc -static"
            CFLAGS="${common_flags} -DWIN32 -D_WIN32 -DXXL_MQTT_STATIC -DBUILD_MQTT_DLL=0 -Wno-comment -finput-charset=utf-8 -fexec-charset=utf-8"
            ;;
    esac

    if [[ "${MQTT_ENABLE_50}" == "1" ]]; then
        lib_dir="${SDK_LIB_ROOT}/${dir_suffix}_v50"
        version_str="v50"
    else
        lib_dir="${SDK_LIB_ROOT}/${dir_suffix}_v311"
        version_str="v311"
    fi

    if [[ "${platform}" == "windows" ]]; then
        SDK_LIB_FILE="${lib_dir}/lib_mqtt_client_sdk_${dir_suffix}_static_${version_str}.${lib_suffix}"
    else
        SDK_LIB_FILE="${lib_dir}/lib_mqtt_client_sdk_${dir_suffix}_${version_str}.${lib_suffix}"
    fi

    TARGET_NAME="${TARGET_BASE_NAME}${DEMO_SUFFIX}_${dir_suffix}${exe}"
    OUTPUT_DIR="${OUTPUT_ROOT}/${dir_suffix}"

    mkdir -p "${OUTPUT_DIR}" || { echo -e "\033[31m[ERROR] 目录创建失败\033[0m"; exit 1; }
    if [[ ! -f "${SDK_LIB_FILE}" ]]; then
        echo -e "\033[31m[ERROR] 库文件缺失：${SDK_LIB_FILE}\033[0m" >&2
        exit 1
    fi

    INC_PARAMS=""
    for dir in "${INC_DIRS[@]}"; do
        [[ -d "${dir}" ]] && INC_PARAMS+=" -I${dir}"
    done
}

collect_c_files() {
    find "${OPEN_SRC_DIRS[@]}" -name "*.c" -type f | sort
}

build_platform() {
    local platform="$1"
    echo -e "\n\033[32m====================================\033[0m" >&2
    echo -e "\033[32m[INFO] 编译${platform}平台\033[0m" >&2
    if [ "$DEBUG_MODE" -eq 1 ]; then
        echo -e "\033[33m[INFO] 调试模式已开启：-O0 -g -ggdb3\033[0m" >&2
    else
        echo -e "\033[32m[INFO] 发行模式：-O2\033[0m" >&2
    fi
    echo -e "\033[32m====================================\033[0m" >&2

    check_deps "${platform}"
    init_platform "${platform}"

    rm -rf "${OUTPUT_DIR}"/*.o
    c_files=($(collect_c_files))
    obj_list=()

    for f in "${c_files[@]}"; do
        name=$(basename "${f}" .c)
        obj="${OUTPUT_DIR}/${name}.o"
        echo -e "\033[32m[INFO] 编译：${f}\033[0m" >&2
        "${CC}" ${CFLAGS} ${INC_PARAMS} -c "${f}" -o "${obj}" || exit 1
        obj_list+=("${obj}")
    done

    target="${OUTPUT_DIR}/${TARGET_NAME}"
    echo -e "\033[32m[INFO] 链接：${target}\033[0m" >&2

    if [[ "${platform}" == "windows" || "${platform}" == "vs2022" ]]; then
        "${CC}" -o "${target}" \
            -Wl,--whole-archive "${SDK_LIB_FILE}" -Wl,--no-whole-archive \
            "${obj_list[@]}" \
            ${LDFLAGS}
    else
        "${CC}" -o "${target}" "${obj_list[@]}" "${SDK_LIB_FILE}" ${LDFLAGS}
    fi

    if [[ -f "${target}" ]]; then
        echo -e "\033[32m[INFO] ✅ 编译成功：${target}\033[0m" >&2
    else
        echo -e "\033[31m[ERROR] 编译失败\033[0m" >&2
        exit 1
    fi

    echo -e "\033[32m[INFO] 清理中间文件\033[0m" >&2
    rm -rf "${OUTPUT_DIR}"/*.o

    echo -e "\033[32m[INFO] ✅ ${platform}编译完成\033[0m" >&2
}

build_all() {
    if [[ "$(uname -s)" =~ "Linux" ]]; then
        echo -e "\033[32m[INFO] 检测Linux环境，编译原生及交叉平台\033[0m" >&2
        build_platform "linux"
        build_platform "arm32"
        build_platform "arm64"
        build_platform "stm32"
    else
        echo -e "\033[32m[INFO] 检测Windows环境，编译Win平台\033[0m" >&2
        build_platform "windows"
        build_platform "vs2022"
    fi
}

main() {
    check_mqtt_dir
    parse_args "$@"

    case "${BUILD_PLATFORM}" in
        linux)      build_platform "linux" ;;
        windows)    build_platform "windows" ;;
        stm32)      build_platform "stm32" ;;
        arm32)      build_platform "arm32" ;;
        arm64)      build_platform "arm64" ;;
        vs2022)     build_platform "vs2022" ;;
        all)        build_all ;;
    esac

    echo -e "\033[31m====================================\033[0m" >&2
    echo -e "\033[31m[MQTT 编译] 全部完成\033[0m" >&2
    echo -e "\033[31m====================================\033[0m" >&2
}

main "$@"
