#!/usr/bin/env bash
# ============================================================
# ruleapi.sh — RuleApi 服务管理脚本（通用 Linux）
# 支持：start / stop / restart / status / watch（宕机自拉起）
# 配置：同目录 ruleapi.config（JAR_NAME/JAR_PATH/JAVA_OPTS/LOG_DIR 等）
# 用法：./ruleapi.sh start | stop | restart | status | watch
# 依赖：ps / pgrep / sleep / curl（可选）
# ============================================================
set -u

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="$SCRIPT_DIR/ruleapi.config"

# ---- 默认值（可被 config 覆盖） ----
JAR_NAME="RuleApiPro.jar"
JAR_PATH="/opt/ruleapi/RuleApiPro.jar"
RUN_USER="root"
JAVA_OPTS="-Xms256m -Xmx1024m -Dspring.config.location=file:/opt/ruleapi/config/application.properties"
LOG_DIR="/log/RuleApi"
WATCH_INTERVAL=30
HEALTH_URL="http://127.0.0.1:8081/install/isInstall"

[ -f "$CONFIG_FILE" ] && . "$CONFIG_FILE"

PID_FILE="$SCRIPT_DIR/ruleapi.pid"
LOG_FILE="$LOG_DIR/ruleapi-console.log"

# ---------- 工具 ----------
get_pid() {
    # 优先 PID 文件，其次 pgrep
    if [ -f "$PID_FILE" ]; then
        local pid
        pid=$(cat "$PID_FILE" 2>/dev/null)
        if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
            echo "$pid"; return 0
        fi
        rm -f "$PID_FILE"
    fi
    pgrep -f "$JAR_NAME" 2>/dev/null | head -1 || true
}

is_running() {
    local pid
    pid=$(get_pid)
    [ -n "$pid" ] && return 0 || return 1
}

precheck_xdb() {
    # IP 属地库必须放在 jar 旁（baseFull.getLocal 从 jar 父目录加载）
    local jar_dir
    jar_dir="$(dirname "$JAR_PATH")"
    local missing=0
    for f in ip2region_v4.xdb ip2region_v6.xdb; do
        if [ ! -f "$jar_dir/$f" ]; then
            echo " [警告] 缺少 $jar_dir/$f —— 请将 $f 复制到 jar 目录，否则 IP 归属地功能不生效"
            missing=1
        fi
    done
    [ "$missing" -eq 1 ] && echo " [提示] 可继续启动（不影响核心功能），建议尽快补齐"
}

# ---------- 子命令 ----------
do_start() {
    if is_running; then
        echo "[start] RuleApi 已在运行 (PID $(get_pid))"
        return 0
    fi
    if [ ! -f "$JAR_PATH" ]; then
        echo "[start] 错误：未找到 $JAR_PATH"
        return 1
    fi
    precheck_xdb

    echo "[start] 启动 RuleApi：$JAR_NAME"
    mkdir -p "$LOG_DIR"
    if [ "$(id -un)" = "$RUN_USER" ] || [ -z "$RUN_USER" ]; then
        nohup java $JAVA_OPTS -jar "$JAR_PATH" >> "$LOG_FILE" 2>&1 &
    else
        # 以指定用户启动（需 root）
        su -s /bin/bash "$RUN_USER" -c "nohup java $JAVA_OPTS -jar '$JAR_PATH' >> '$LOG_FILE' 2>&1 &"
    fi
    local pid=$!
    echo "$pid" > "$PID_FILE"
    echo "[start] 已启动 PID=$pid，日志：$LOG_FILE"
    # 等待端口就绪（最多 30s）
    for i in $(seq 1 30); do
        if curl -s -o /dev/null --max-time 2 "$HEALTH_URL" 2>/dev/null; then
            echo "[start] 健康检查通过（$HEALTH_URL）"
            return 0
        fi
        sleep 1
    done
    echo "[start] 已启动但 30s 内未通过健康检查，请查看日志：$LOG_FILE"
    return 0
}

do_stop() {
    if ! is_running; then
        echo "[stop] RuleApi 未在运行"
        rm -f "$PID_FILE"
        return 0
    fi
    local pid
    pid=$(get_pid)
    echo "[stop] 停止 PID=$pid ..."
    kill "$pid" 2>/dev/null
    for i in $(seq 1 10); do
        if ! kill -0 "$pid" 2>/dev/null; then
            break
        fi
        sleep 1
    done
    if kill -0 "$pid" 2>/dev/null; then
        echo "[stop] 优雅停止超时，强制 kill -9"
        kill -9 "$pid" 2>/dev/null
    fi
    rm -f "$PID_FILE"
    echo "[stop] 已停止"
}

do_restart() {
    echo "[restart] 重启 RuleApi ..."
    do_stop
    sleep 2
    do_start
}

do_status() {
    if is_running; then
        local pid
        pid=$(get_pid)
        echo "[status] RuleApi：运行中 (PID=$pid)"
        echo "         JAR:   $JAR_PATH"
        echo "         PID:   $pid"
        # 端口（尝试从配置提取或 ss 探测）
        local port
        port=$(echo "$JAVA_OPTS" "$CONFIG" | grep -oE '_PORT_[0-9]+' >/dev/null 2>&1; echo "")
        ss -ltnp 2>/dev/null | grep -E ":$port|java" | head -3 || true
        echo "         日志:  $LOG_FILE"
        tail -n 6 "$LOG_FILE" 2>/dev/null | sed 's/^/         | /'
    else
        echo "[status] RuleApi：未运行"
        return 1
    fi
}

do_watch() {
    echo "[watch] 状态监听启动：每 ${WATCH_INTERVAL}s 检查一次（Ctrl+C 退出）"
    local restart_count=0
    while true; do
        if ! is_running; then
            restart_count=$((restart_count + 1))
            echo "[watch] $(date '+%F %T') 检测到进程不在，自动拉起（第 ${restart_count} 次）"
            do_start
        else
            :
        fi
        sleep "$WATCH_INTERVAL"
    done
}

# ---------- 入口 ----------
case "${1:-}" in
    start)   do_start ;;
    stop)    do_stop ;;
    restart) do_restart ;;
    status)  do_status ;;
    watch)   do_watch ;;
    *)
        echo "用法: $0 {start|stop|restart|status|watch}"
        echo "  start    启动服务（含 ip2region xdb 前置检查）"
        echo "  stop     优雅停止服务"
        echo "  restart  重启服务"
        echo "  status   查看运行状态/日志尾部"
        echo "  watch    状态监听：宕机自动拉起（Ctrl+C 退出）"
        exit 1
        ;;
esac