#!/bin/bash

# ============================================================
# 一键部署脚本 (2核4G 低配服务器优化版)
# 用法: ./deploy.sh [admin|miniapp|all] [--skip-frontend] [--no-stop]
#       --no-stop  构建前不停止服务 (零停机，JVM 已限制内存)
# 调试: bash -x ./deploy.sh
# ============================================================

APP_DIR="/data/app"
CODE_DIR="/data/code/car-wash-java"
BACKUP_DIR="/data/backup"
LOG_DIR="/data/logs"
HISTORY_FILE="/data/history"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

log()   { echo -e "[$(date '+%H:%M:%S')] $1"; }
info()  { log "${GREEN}INFO${NC}  $1"; }
warn()  { log "${YELLOW}WARN${NC}  $1"; }
error() { log "${RED}ERROR${NC} $1"; }

mkdir -p "$LOG_DIR" "$BACKUP_DIR"

# ============================================================
# 资源限制配置 (2核4G 服务器)
# ============================================================

# ---- 构建阶段 ----
NODE_MAX_MEM="${NODE_MAX_MEM:-1024}"      # Node 最大 old-space MB
MAVEN_XMX="${MAVEN_XMX:-512}"             # Maven JVM 最大堆 MB
MAVEN_XMS="${MAVEN_XMS:-128}"             # Maven JVM 初始堆 MB
MAVEN_THREADS="${MAVEN_THREADS:-1}"       # Maven 编译线程数

# ---- 运行时 JVM (admin 模块) ----
ADMIN_XMX="${ADMIN_XMX:-512}"             # 最大堆 MB (含 POI Excel 处理)
ADMIN_XMS="${ADMIN_XMS:-128}"             # 初始堆 MB
ADMIN_META="${ADMIN_META:-128}"           # 元空间上限 MB
ADMIN_CODE_CACHE="${ADMIN_CODE_CACHE:-64}" # JIT 代码缓存 MB
ADMIN_XSS="${ADMIN_XSS:-256}"             # 线程栈 KB

# ---- 运行时 JVM (miniapp 模块) ----
MINIAPP_XMX="${MINIAPP_XMX:-384}"
MINIAPP_XMS="${MINIAPP_XMS:-128}"
MINIAPP_META="${MINIAPP_META:-256}"
MINIAPP_CODE_CACHE="${MINIAPP_CODE_CACHE:-64}"
MINIAPP_XSS="${MINIAPP_XSS:-256}"

# 低优先级包装器
low_prio() {
    nice -n 19 ionice -c 2 -n 7 "$@"
}

# ---- 参数解析 ----
TARGET="${1:-all}"
SKIP_FRONTEND=false
NO_STOP=false
for arg in "$@"; do
    [ "$arg" = "--skip-frontend" ] && SKIP_FRONTEND=true
    [ "$arg" = "--no-stop" ] && NO_STOP=true
done

info "开始部署 (目标=$TARGET, 零停机=$NO_STOP)"
info "Node:${NODE_MAX_MEM}M | Maven:${MAVEN_XMX}M | Admin-JVM:${ADMIN_XMX}M | Miniapp-JVM:${MINIAPP_XMX}M"

# ---- 拉取代码 ----
info "拉取最新代码..."
cd "$CODE_DIR" || { error "无法进入 $CODE_DIR"; exit 1; }
low_prio git pull origin master || { error "git pull 失败"; exit 1; }

# ============================================================
# 阶段 1: 停止服务 (释放内存给构建)
# ============================================================
stop_service() {
    local module=$1
    local pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}')

    if [ -z "$pid" ]; then
        info "$module 未在运行"
        return 0
    fi

    for p in $pid; do
        info "终止 $module (pid=$p)..."
        kill "$p" 2>/dev/null

        for i in $(seq 1 10); do
            if ! kill -0 "$p" 2>/dev/null; then
                info "进程 $p 已退出"
                break
            fi
            sleep 1
        done

        if kill -0 "$p" 2>/dev/null; then
            warn "强制终止 $p"
            kill -9 "$p" 2>/dev/null
            sleep 1
        fi
    done
}

if [ "$NO_STOP" = false ]; then
    case "$TARGET" in
        admin)   stop_service "car-wash-admin" ;;
        miniapp) stop_service "car-wash-miniapp" ;;
        all)     stop_service "car-wash-admin"
                 stop_service "car-wash-miniapp" ;;
    esac
    sleep 3
fi

# ============================================================
# 阶段 2: 构建
# ============================================================

if [ "$SKIP_FRONTEND" = false ] && [ "$TARGET" != "miniapp" ]; then
    for item in "admin-web:admin-web" "admin-h5:admin-h5"; do
        dir="${item%%:*}"
        name="${item##*:}"
        info "构建前端 $name ..."
        (
            cd "$CODE_DIR/$dir" || exit 1
            export NODE_OPTIONS="--max-old-space-size=$NODE_MAX_MEM"
            low_prio npm run build
        ) || { error "$name 构建失败"; exit 1; }
        info "$name 构建完成"
        sleep 2
    done
    info "前端构建全部完成"
fi

export MAVEN_OPTS="-Xmx${MAVEN_XMX}m -Xms${MAVEN_XMS}m -XX:+UseSerialGC"

if [ "$TARGET" = "miniapp" ]; then
    info "Maven 打包 (仅 miniapp)..."
    (
        cd "$CODE_DIR"
        low_prio mvn clean package -DskipTests -pl car-wash-miniapp -am \
            -T "${MAVEN_THREADS}" -Dmaven.test.skip=true
    ) || { error "Maven 打包失败"; exit 1; }
else
    info "Maven 打包 (全量, 线程=${MAVEN_THREADS})..."
    (
        cd "$CODE_DIR"
        low_prio mvn clean package -DskipTests \
            -T "${MAVEN_THREADS}" \
            -Dmaven.test.skip=true \
            -Dmaven.compiler.fork=false
    ) || { error "Maven 打包失败"; exit 1; }
fi

sleep 2

# ============================================================
# 阶段 3: 备份 & 部署 & 启动
# ============================================================

backup_and_copy() {
    local module=$1
    local jar_src="$CODE_DIR/$module/target/${module}-0.0.1-SNAPSHOT.jar"
    local jar_dst="$APP_DIR/${module}-0.0.1-SNAPSHOT.jar"

    if [ ! -f "$jar_src" ]; then
        error "未找到 jar 文件: $jar_src"
        exit 1
    fi

    if [ -f "$jar_dst" ]; then
        cp "$jar_dst" "$BACKUP_DIR/${module}-0.0.1-SNAPSHOT.jar.$(date +%Y%m%d_%H%M%S)"
        info "已备份 $module (保留最近 5 个)"
        ls -t "$BACKUP_DIR/${module}"-*.jar 2>/dev/null | tail -n +6 | xargs -r rm -f
    fi
    cp "$jar_src" "$jar_dst"
    info "$module jar 已复制到 $APP_DIR"
}

# 构建模块专用的 JVM 参数
build_jvm_opts() {
    local module=$1
    if [ "$module" = "car-wash-admin" ]; then
        echo "-Xmx${ADMIN_XMX}m -Xms${ADMIN_XMS}m -Xss${ADMIN_XSS}k \
-XX:MaxMetaspaceSize=${ADMIN_META}m -XX:ReservedCodeCacheSize=${ADMIN_CODE_CACHE}m \
-XX:+UseSerialGC -XX:+UseStringDeduplication"
    else
        echo "-Xmx${MINIAPP_XMX}m -Xms${MINIAPP_XMS}m -Xss${MINIAPP_XSS}k \
-XX:MaxMetaspaceSize=${MINIAPP_META}m -XX:ReservedCodeCacheSize=${MINIAPP_CODE_CACHE}m \
-XX:+UseSerialGC -XX:+UseStringDeduplication"
    fi
}

start_service() {
    local module=$1
    local jar_file="${module}-0.0.1-SNAPSHOT.jar"
    local start_log="$LOG_DIR/${module}.log"
    local jvm_opts=$(build_jvm_opts "$module")

    info "启动 $module (JVM: $(echo $jvm_opts | tr -s ' '))..."

    local cert_arg=""
    if [ "$module" = "car-wash-admin" ]; then
        cert_arg="-Dwechat.payment.certPath=/data/wash-pem/apiclient_cert.pem -Dwechat.payment.keyPath=/data/wash-pem/apiclient_key.pem"
    fi

    cd "$APP_DIR"
    nohup java $jvm_opts -jar -Dspring.profiles.active=prod $cert_arg "$jar_file" > "$start_log" 2>&1 &

    sleep 5
    local new_pid=$(ps -ef | grep java | grep "$module" | grep -v grep | awk '{print $2}')

    if [ -n "$new_pid" ]; then
        info "$module 启动成功 (pid=$new_pid)"
        echo "$(date) $module restarted" >> "$HISTORY_FILE"
    else
        error "$module 可能启动失败，查看日志:"
        echo "--- $start_log ---"
        tail -30 "$start_log"
        echo "--- end ---"
        exit 1
    fi
}

case "$TARGET" in
    admin)
        backup_and_copy "car-wash-admin"
        start_service "car-wash-admin"
        ;;
    miniapp)
        backup_and_copy "car-wash-miniapp"
        start_service "car-wash-miniapp"
        ;;
    all)
        backup_and_copy "car-wash-admin"
        backup_and_copy "car-wash-miniapp"
        start_service "car-wash-admin"
        start_service "car-wash-miniapp"
        ;;
    *)
        error "未知模块: $TARGET (可选: admin | miniapp | all)"
        exit 1
        ;;
esac

echo "========================================"
info "部署完成"
echo "========================================"
