#!/bin/bash
# MQTT Client SDK SHARED Library 编译脚本（上层APP动态库组件）
# 功能：编译 上层APP使用的MQTT客户端动态库/静态库
# 输出规范：
#    Linux/ARM32/ARM64  => .so (shared)
#    Windows/VS2022     => .dll (shared)
#    STM32              => .a  (static)
# 不编译 examples，链接底层协议内核库
# 所有平台都不编译 lwip，由客户工程自行提供
# ==============================================================================

# ==================== 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[32m====================================\033[0m" >&2
echo -e "\033[32m[MQTT CLIENT SDK SHARED] 编译上层动态库组件\033[0m" >&2
echo -e "\033[32m====================================\033[0m" >&2
sleep 0.3

# ==================== 核心目录配置（不含examples）====================
COMMON_DIRS=(
    "./comm"
    "./crypto"
)

# ==================== 平台目录 ====================
LINUX_DIRS=(
    "./os"
    "./network"
)

WIN_DIRS=(
    "./os"
    "./network"
)

STM32_DIRS=(
    "./os"
    "./network"
)

INC_DIRS=(
    "./"
    "./comm"
    "./os"
    "./network"
    "./client_core"
    "./protocol"
    "./lib"
    "./crypto"
    "./lwip/src/include"
    "./Drivers/CMSIS/Include"
    "./Drivers/CMSIS/Device/ST/STM32F4xx/Include"
    "./Drivers/STM32F4xx_HAL_Driver/Inc"
)

SDK_LIB_ROOT="./lib"
OUTPUT_ROOT="./sdk_shared"
TARGET_BASE_NAME="libmqtt_client_sdk"

# 交叉编译器配置
ARM32_CC="arm-linux-gnueabihf-gcc"
ARM64_CC="aarch64-linux-gnu-gcc"
STM32_CC="arm-none-eabi-gcc"
STM32_AR="arm-none-eabi-ar"
STM32_CPU="cortex-m4"

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

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

# ==================== 帮助 ====================
show_help() {
    echo -e "\033[32m==== MQTT CLIENT SDK SHARED 编译 ====\033[0m" >&2
    echo "用法：$0 [-p|--platform <平台>] [-v|--version 311|50] [-d|--debug]" >&2
    echo "平台：linux windows stm32 arm32 arm64 vs2022 all" >&2
    echo "版本：-v 311  MQTT 3.1.1" >&2
    echo "      -v 50   MQTT 5.0" >&2
    echo "输出目录：sdk_shared/" >&2
    exit 0
}

check_mqtt_dir() {
    echo -e "\033[32m[INFO] 校验目录结构...\033[0m" >&2
    local required_dirs=("comm" "os" "network" "lib" "crypto")
    for dir in "${required_dirs[@]}"
    do
        if [[ ! -d "${SCRIPT_DIR}/${dir}" ]]; then
            echo -e "\033[31m[ERROR] 缺失目录：${dir}\033[0m" >&2
            exit 1
        fi
    done
    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
                ;;
            -v|--version)
                if [ "$2" = "50" ]; then
                    MQTT_ENABLE_50="1"
                else
                    MQTT_ENABLE_50="0"
                fi
                shift 2
                ;;
            -d|--debug)
                DEBUG_MODE="1"
                shift
                ;;
            -h|--help)
                show_help
                ;;
            *)
                echo -e "\033[31m[ERROR] 无效参数：$1\033[0m" >&2
                exit 1
                ;;
        esac
    done

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

    [ "$MQTT_ENABLE_50" = "1" ] && VERSION_SUFFIX="_v50" || VERSION_SUFFIX="_v311"
}

init_platform() {
    local platform="$1"
    rm -f "${ERROR_LOG}"

    DEMO_DEFINES="
-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)      dir_suffix="linux"; lib_ext="a"; out_ext="so" ;;
        windows)    dir_suffix="windows"; lib_ext="lib"; out_ext="dll" ;;
        stm32)      dir_suffix="stm32"; lib_ext="a"; out_ext="a" ;;
        arm32)      dir_suffix="arm32"; lib_ext="a"; out_ext="so" ;;
        arm64)      dir_suffix="arm64"; lib_ext="a"; out_ext="so" ;;
        vs2022)     dir_suffix="vs2022"; lib_ext="lib"; out_ext="dll" ;;
    esac

    lib_dir="${SDK_LIB_ROOT}/${dir_suffix}${VERSION_SUFFIX}"
    SDK_LIB_FILE="${lib_dir}/lib_mqtt_client_sdk_${dir_suffix}${VERSION_SUFFIX}.${lib_ext}"
    OUTPUT_DIR="${OUTPUT_ROOT}/${dir_suffix}${VERSION_SUFFIX}"
    mkdir -p "${OUTPUT_DIR}"

    if [[ ! -f "${SDK_LIB_FILE}" ]]; then
        echo -e "\033[31m[ERROR] 库不存在：${SDK_LIB_FILE}\033[0m" >&2
        exit 1
    fi

    case "${platform}" in
        linux)
            CC="gcc"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            LDFLAGS="-lpthread -lrt -shared"
            ;;
        windows)
            CC="gcc"
            # 🔥 🔥 🔥 关键修复：编译DLL时启用导出
            CFLAGS="${common_flags} -DWIN32 -D_WIN32 -DBUILD_MQTT_DLL -fPIC"
            LDFLAGS="-shared -lws2_32 -lbcrypt -static-libgcc -Wl,--export-all-symbols"
            ;;
        stm32)
            CC="${STM32_CC}"
            AR="${STM32_AR}"
            CFLAGS="${common_flags} -DSTM32 -DSTM32F407xx -mcpu=${STM32_CPU} -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections"
            LDFLAGS=""
            ;;
        arm32)
            CC="${ARM32_CC}"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            LDFLAGS="-lpthread -shared"
            ;;
        arm64)
            CC="${ARM64_CC}"
            CFLAGS="${common_flags} -DLINUX -fPIC"
            LDFLAGS="-lpthread -shared"
            ;;
        vs2022)
            CC="x86_64-w64-mingw32-gcc"
            # 🔥 🔥 🔥 关键修复：编译DLL时启用导出
            CFLAGS="${common_flags} -DWIN32 -D_WIN32 -DBUILD_MQTT_DLL -fPIC"
            LDFLAGS="-shared -lws2_32 -lbcrypt -static-libgcc -Wl,--export-all-symbols"
            ;;
    esac

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

collect_c_files() {
    local platform="$1"
    local dirs=("${COMMON_DIRS[@]}")

    if [[ "$platform" == "linux" || "$platform" == "arm32" || "$platform" == "arm64" ]]; then
        dirs+=("${LINUX_DIRS[@]}")
    elif [[ "$platform" == "windows" || "$platform" == "vs2022" ]]; then
        dirs+=("${WIN_DIRS[@]}")
    elif [[ "$platform" == "stm32" ]]; then
        dirs+=("${STM32_DIRS[@]}")
    fi

    find "${dirs[@]}" -name "*.c" -type f | sort
}

build_platform() {
    local platform="$1"

    # ========== 非STM32平台：完全保留原有逻辑，无任何修改 ==========
    if [[ "${platform}" != "stm32" ]]; then
        echo -e "\n\033[32m====================================\033[0m" >&2
        echo -e "\033[32m[INFO] 编译 ${platform} ${VERSION_SUFFIX} SHARED\033[0m" >&2
        echo -e "\033[32m====================================\033[0m" >&2

        init_platform "${platform}"
        c_files=($(collect_c_files "${platform}"))
        obj_list=()

        rm -rf "${OUTPUT_DIR}"/*.o

        for f in "${c_files[@]}"; do
            if [[ "$platform" == "windows" || "$platform" == "vs2022" ]]; then
                if [[ "$f" == *"linux"* || "$f" == *"stm32"* ]]; then continue; fi
            fi
            if [[ "$platform" == "linux" || "$platform" == "arm32" || "$platform" == "arm64" ]]; then
                if [[ "$f" == *"win32"* || "$f" == *"stm32"* ]]; then continue; fi
            fi

            obj="${OUTPUT_DIR}/$(basename "${f}" .c).o"
            echo -e "\033[32m[INFO] 编译：${f}\033[0m" >&2
            "${CC}" ${CFLAGS} ${INC_PARAMS} -c "${f}" -o "${obj}"
            obj_list+=("${obj}")
        done

        out_lib="${OUTPUT_DIR}/${TARGET_BASE_NAME}_${dir_suffix}${VERSION_SUFFIX}.${out_ext}"
        "${CC}" -o "${out_lib}" "${obj_list[@]}" -Wl,--whole-archive ${SDK_LIB_FILE} -Wl,--no-whole-archive ${LDFLAGS}

        if [ ! -f "${out_lib}" ]; then
            echo -e "\033[31m[ERROR] 编译失败，未生成库文件！\033[0m" >&2
            exit 1
        fi

        rm -rf "${OUTPUT_DIR}"/*.o
        echo -e "\033[32m✅ 生成库：${out_lib}\033[0m" >&2
        return
    fi

    # ========== 仅 STM32 分支：拆分 GCC / KEIL 双版本 ==========
# 1. STM32-GCC （CubeIDE / CubeMX）======= 【已修复：clean 编译】=======
echo -e "\n\033[32m====================================\033[0m" >&2
echo -e "\033[32m[INFO] 编译 STM32_GCC ${VERSION_SUFFIX} SHARED\033[0m" >&2
echo -e "\033[32m====================================\033[0m" >&2

CC="${STM32_CC}"
AR="${STM32_AR}"
DEMO_DEFINES="-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 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -fno-stack-protector"
CFLAGS="${common_flags} -DSTM32 -DSTM32F407xx -mcpu=${STM32_CPU} -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections"

dir_suffix="stm32_gcc"
OUTPUT_DIR="${OUTPUT_ROOT}/${dir_suffix}${VERSION_SUFFIX}"
mkdir -p "${OUTPUT_DIR}"

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

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

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

    out_lib="${OUTPUT_DIR}/${TARGET_BASE_NAME}_${dir_suffix}${VERSION_SUFFIX}.a"
    ${AR} rcs "${out_lib}" ${obj_list[@]}
# ===================== 【重要】删除旧库合并逻辑 =====================
# abs_lib=$(readlink -f "${SDK_LIB_FILE}")
# abs_out=$(readlink -f "${out_lib}")
# tmp_dir="${OUTPUT_DIR}/tmp"
# mkdir -p "${tmp_dir}"
# cd "${tmp_dir}"
# ${AR} x "${abs_lib}"
# ${AR} q "${abs_out}" ./*
# cd - > /dev/null
# rm -rf "${tmp_dir}"
# ====================================================================

rm -rf "${OUTPUT_DIR}"/*.o
    echo -e "\033[32m✅ 生成STM32_GCC库：${out_lib}\033[0m" >&2

    # 2. STM32-KEIL （AC5 微库）
    echo -e "\n\033[32m====================================\033[0m" >&2
    echo -e "\033[32m[INFO] 编译 STM32_KEIL ${VERSION_SUFFIX} SHARED\033[0m" >&2
    echo -e "\033[32m====================================\033[0m" >&2

    CC="${STM32_CC}"
    AR="${STM32_AR}"
    DEMO_DEFINES="-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 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -fno-stack-protector"
    CFLAGS="${common_flags} -DSTM32 -DSTM32F407xx -mcpu=${STM32_CPU} -mthumb -mfloat-abi=soft -mfpu=fpv4-sp-d16 -ffunction-sections -fdata-sections -D__MICROLIB -fshort-wchar"
    
    dir_suffix="stm32_keil"
    lib_dir="${SDK_LIB_ROOT}/stm32_keil${VERSION_SUFFIX}"
    SDK_LIB_FILE="${lib_dir}/lib_mqtt_client_sdk_stm32_keil${VERSION_SUFFIX}.lib"
    OUTPUT_DIR="${OUTPUT_ROOT}/stm32_keil${VERSION_SUFFIX}"
    mkdir -p "${OUTPUT_DIR}"

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

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

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

    out_lib="${OUTPUT_DIR}/${TARGET_BASE_NAME}_${dir_suffix}${VERSION_SUFFIX}.a"
    ${AR} rcs "${out_lib}" ${obj_list[@]}
    abs_lib=$(readlink -f "${SDK_LIB_FILE}")
    abs_out=$(readlink -f "${out_lib}")
    tmp_dir="${OUTPUT_DIR}/tmp"
    mkdir -p "${tmp_dir}"
    cd "${tmp_dir}"
    ${AR} x "${abs_lib}"
    ${AR} q "${abs_out}" ./*
    cd - > /dev/null
    rm -rf "${tmp_dir}"
    rm -rf "${OUTPUT_DIR}"/*.o
    echo -e "\033[32m✅ 生成STM32_KEIL库：${out_lib}\033[0m" >&2
}

build_all() {
    if [[ "$(uname -s)" =~ "Linux" ]]; then
        build_platform "linux"
        build_platform "arm32"
        build_platform "arm64"
        build_platform "stm32"
    else
        build_platform "windows"
        build_platform "vs2022"
    fi
}

main() {
    check_mqtt_dir
    parse_args "$@"

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

    echo -e "\n\033[32m========================================"
    echo "✅ MQTT CLIENT SDK SHARED 编译完成！"
    echo "📦 输出目录：sdk_shared/"
    echo "  Linux/ARM    => .so"
    echo "  Windows/VS   => .dll"
    echo "  STM32        => .a"
    echo -e "========================================\033[0m"
}

main "$@"
