#!/bin/sh

set -eu

JAVA_BIN="/home/webapp/env/java/bin/java"
BACKEND_PORT=63310
SPRING_PROFILE="uat"
JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"

SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
BACKEND_DIR="$SCRIPT_DIR/backend"
FRONTEND_DIR="$SCRIPT_DIR/frontend"
BACKEND_JAR_TARGET="$BACKEND_DIR/ruoyi-admin.jar"
BACKEND_PID_FILE="$BACKEND_DIR/backend.pid"
BACKEND_LOG_FILE="$BACKEND_DIR/backend-console.log"
FRONTEND_DIST_ARCHIVE="$FRONTEND_DIR/dist.zip"
FRONTEND_DIST_DIR="$FRONTEND_DIR/dist"
BACKEND_MARKER="-Dloan.pricing.home=$SCRIPT_DIR"

usage() {
    cat <<'EOF'
用法:
  ./deploy_from_package.sh
EOF
}

timestamp() {
    date "+%Y%m%d%H%M%S"
}

log_info() {
    printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"
}

log_error() {
    printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >&2
}

cleanup() {
    if [ -n "${WORK_DIR:-}" ] && [ -d "$WORK_DIR" ]; then
        rm -rf "$WORK_DIR"
    fi
}

require_dir() {
    if [ ! -d "$1" ]; then
        log_error "缺少目录: $1"
        exit 1
    fi
}

require_command() {
    if ! command -v "$1" >/dev/null 2>&1; then
        log_error "缺少命令: $1"
        exit 1
    fi
}

find_release_archive() {
    archives=$(find "$SCRIPT_DIR" -maxdepth 1 -type f -name '*.zip' ! -name 'dist.zip')
    count=$(printf '%s\n' "$archives" | sed '/^$/d' | wc -l | tr -d ' ')

    if [ "$count" -ne 1 ]; then
        log_error "脚本同目录发布 zip 数量不正确，期望 1 个，实际 $count 个"
        exit 1
    fi

    printf '%s\n' "$archives"
}

extract_release_package() {
    release_archive="$1"
    release_extract_dir="$2"

    mkdir -p "$release_extract_dir"
    unzip -oq "$release_archive" -d "$release_extract_dir"
}

assert_single_jar() {
    search_dir="$1"
    count=$(find "$search_dir" -type f -name '*.jar' ! -path '*/__MACOSX/*' ! -name '._*' | wc -l | tr -d ' ')

    if [ "$count" -ne 1 ]; then
        log_error "后端 jar 数量不正确，期望 1 个，实际 $count 个"
        exit 1
    fi

    find "$search_dir" -type f -name '*.jar' ! -path '*/__MACOSX/*' ! -name '._*' | head -n 1
}

assert_single_dist_zip() {
    search_dir="$1"
    count=$(find "$search_dir" -type f -name 'dist.zip' ! -path '*/__MACOSX/*' ! -name '._*' | wc -l | tr -d ' ')

    if [ "$count" -ne 1 ]; then
        log_error "前端 dist.zip 数量不正确，期望 1 个，实际 $count 个"
        exit 1
    fi

    find "$search_dir" -type f -name 'dist.zip' ! -path '*/__MACOSX/*' ! -name '._*' | head -n 1
}

backup_backend_jar() {
    if [ -f "$BACKEND_JAR_TARGET" ]; then
        mv "$BACKEND_JAR_TARGET" "$BACKEND_JAR_TARGET.$(timestamp).bak"
    fi
}

backup_frontend_dist() {
    if [ -d "$FRONTEND_DIST_DIR" ]; then
        mv "$FRONTEND_DIST_DIR" "$FRONTEND_DIR/dist-$(timestamp)"
    fi
}

deploy_backend_jar() {
    source_jar="$1"
    mv "$source_jar" "$BACKEND_JAR_TARGET"
}

deploy_frontend_dist() {
    source_dist_zip="$1"
    rm -f "$FRONTEND_DIST_ARCHIVE"
    rm -rf "$FRONTEND_DIST_DIR"
    mv "$source_dist_zip" "$FRONTEND_DIST_ARCHIVE"
    unzip -oq "$FRONTEND_DIST_ARCHIVE" -d "$FRONTEND_DIR"

    if [ ! -d "$FRONTEND_DIST_DIR" ]; then
        log_error "dist.zip 解压后未找到 $FRONTEND_DIST_DIR"
        exit 1
    fi
}

collect_backend_pids() {
    ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR_TARGET" '
        index($0, "<defunct>") == 0 && index($0, marker) > 0 {
            for (i = 1; i < NF; i++) {
                if ($i == "-jar" && $(i + 1) == jar) {
                    print $2
                    break
                }
            }
        }
    ' | xargs 2>/dev/null || true
}

stop_backend() {
    pids=$(collect_backend_pids)

    if [ -z "${pids:-}" ]; then
        rm -f "$BACKEND_PID_FILE"
        log_info "未发现运行中的后端进程"
        return 0
    fi

    log_info "停止后端进程: $pids"
    for pid in $pids; do
        kill -TERM "$pid" 2>/dev/null || true
    done

    elapsed=0
    remaining="$pids"
    while [ "$elapsed" -lt 30 ]; do
        remaining=""
        for pid in $pids; do
            if kill -0 "$pid" 2>/dev/null; then
                remaining="$remaining $pid"
            fi
        done

        remaining=$(echo "$remaining" | xargs 2>/dev/null || true)
        if [ -z "${remaining:-}" ]; then
            break
        fi

        sleep 1
        elapsed=$((elapsed + 1))
    done

    if [ -n "${remaining:-}" ]; then
        log_info "执行强制停止: $remaining"
        for pid in $remaining; do
            kill -KILL "$pid" 2>/dev/null || true
        done
    fi

    rm -f "$BACKEND_PID_FILE"
}

start_backend() {
    if [ ! -x "$JAVA_BIN" ]; then
        log_error "未检测到可执行 Java: $JAVA_BIN"
        exit 1
    fi

    if [ ! -f "$BACKEND_JAR_TARGET" ]; then
        log_error "未找到后端 jar: $BACKEND_JAR_TARGET"
        exit 1
    fi

    if [ -n "$(collect_backend_pids)" ]; then
        log_error "检测到后端已在运行，请先停止旧进程"
        exit 1
    fi

    printf '\n===== %s deploy =====\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$BACKEND_LOG_FILE"

    nohup "$JAVA_BIN" $JAVA_OPTS "$BACKEND_MARKER" -jar "$BACKEND_JAR_TARGET" \
        --spring.profiles.active="$SPRING_PROFILE" \
        --server.port="$BACKEND_PORT" >> "$BACKEND_LOG_FILE" 2>&1 &
    backend_pid=$!
    printf '%s\n' "$backend_pid" > "$BACKEND_PID_FILE"

    sleep 1

    if ! kill -0 "$backend_pid" 2>/dev/null; then
        log_error "后端启动失败，请检查日志: $BACKEND_LOG_FILE"
        exit 1
    fi

    log_info "后端已启动，PID: $backend_pid"
}

main() {
    if [ "$#" -ne 0 ]; then
        usage
        exit 1
    fi

    require_dir "$BACKEND_DIR"
    require_dir "$FRONTEND_DIR"
    require_command unzip
    require_command find
    require_command ps
    require_command nohup

    release_archive=$(find_release_archive)
    WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/deploy_from_package.XXXXXX")
    trap cleanup EXIT INT TERM

    extract_release_package "$release_archive" "$WORK_DIR/package"

    backend_jar_source=$(assert_single_jar "$WORK_DIR/package")
    frontend_dist_source=$(assert_single_dist_zip "$WORK_DIR/package")

    backup_backend_jar
    backup_frontend_dist
    stop_backend
    deploy_backend_jar "$backend_jar_source"
    deploy_frontend_dist "$frontend_dist_source"
    start_backend

    log_info "部署完成"
    log_info "后端 jar: $BACKEND_JAR_TARGET"
    log_info "前端目录: $FRONTEND_DIST_DIR"
}

main "$@"
