#!/usr/bin/env bash

# 统一管理脚本：启动/停止/查看 四个 API 服务
# 支持服务：
#  - intent      -> rag2_0.api.intent_recognition_api:app   (port 8001, workers 25)
#  - dify        -> rag2_0.api.DifyQueryRetrieval_api:app   (port 8002, workers 25)
#  - answertype  -> rag2_0.api.AnswerType_api:app           (port 8003, workers 1)
#  - qingdan     -> rag2_0.api.query_dinge_qingdan_api:app  (port 8005, workers 1)

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# 定义服务配置：会话名 与 启动命令
SERVICE_NAMES=(intent dify answertype qingdan)

service_port() {
  case "$1" in
    intent) echo "8001" ;;
    dify) echo "8002" ;;
    answertype) echo "8003" ;;
    qingdan) echo "8005" ;;
    *) echo "" ;;
  esac
}

session_name() {
  case "$1" in
    intent) echo "intent_recognition_api" ;;
    dify) echo "DifyQueryRetrieval_api" ;;
    answertype) echo "AnswerType" ;;
    qingdan) echo "query_dinge_qingdan_api" ;;
    *) echo "" ;;
  esac
}

start_command() {
  case "$1" in
    intent)
      echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.intent_recognition_api:app --host 0.0.0.0 --port 8001 --workers 4" ;;
    dify)
      echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.DifyQueryRetrieval_api:app --host 0.0.0.0 --port 8002 --workers 4" ;;
    answertype)
      echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.AnswerType_api:app --host 0.0.0.0 --port 8003 --workers 1" ;;
    qingdan)
      echo "cd \"$SCRIPT_DIR\" && uv run uvicorn rag2_0.api.query_dinge_qingdan_api:app --host 0.0.0.0 --port 8005 --workers 4" ;;
    *) echo "" ;;
  esac
}

exists_session() {
  # 使用严格匹配，避免误判
  local name="$1"
  if screen -ls 2>/dev/null | grep -q "\\.${name}\\s"; then
    return 0
  fi
  return 1
}

# 按端口获取监听该端口的任意一个PID，优先用 ss，其次 lsof
pids_on_port() {
  local port="$1"
  # 从 ss 提取 pid 列表
  local ss_pids
  ss_pids=$(ss -lptn 2>/dev/null \
    | grep -E ":${port}\\b" \
    | awk '{print $NF}' \
    | sed -n 's/.*pid=\([0-9]\+\),.*/\1/p' \
    | sort -u)
  if [[ -n "$ss_pids" ]]; then
    echo "$ss_pids"
    return 0
  fi
  # 从 lsof 提取 pid 列表
  if command -v lsof >/dev/null 2>&1; then
    local lsof_pids
    lsof_pids=$(lsof -nP -i :"$port" -sTCP:LISTEN -t 2>/dev/null | sort -u)
    if [[ -n "$lsof_pids" ]]; then
      echo "$lsof_pids"
      return 0
    fi
  fi
  return 1
}

# 根据端口优雅终止(TERM)并在必要时强制(KILL)清理进程
kill_by_port() {
  local port="$1"
  local pids
  pids=$(pids_on_port "$port" || true)
  if [[ -z "$pids" ]]; then
    return 0
  fi
  echo "[清理] 端口 $port 仍被占用，发送 SIGTERM 到: $pids"
  kill -TERM $pids 2>/dev/null || true
  sleep 2
  # 再次检查
  local left
  left=$(pids_on_port "$port" || true)
  if [[ -n "$left" ]]; then
    echo "[强制] 端口 $port 仍占用，发送 SIGKILL 到: $left"
    kill -KILL $left 2>/dev/null || true
  fi
}

start_service() {
  local svc="$1"
  local sname
  sname="$(session_name "$svc")"
  if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
  if exists_session "$sname"; then
    echo "[跳过] 会话 '$sname' 已存在"
    return 0
  fi
  local cmd
  cmd="$(start_command "$svc")"
  if [[ -z "$cmd" ]]; then echo "未配置启动命令: $svc"; return 2; fi
  screen -dmS "$sname" bash -c "$cmd"
  echo "[启动] $svc -> screen 会话 '$sname'"
}

stop_service() {
  local svc="$1"
  local sname
  sname="$(session_name "$svc")"
  local port
  port="$(service_port "$svc")"
  if [[ -z "$sname" || -z "$port" ]]; then echo "未知服务: $svc"; return 2; fi

  # 1) 先尝试关闭 screen 会话
  if exists_session "$sname"; then
    screen -S "$sname" -X quit || true
    echo "[停止] $svc -> '$sname'"
  else
    echo "[提示] 未发现 screen 会话: $sname"
  fi

  # 2) 等待释放端口
  sleep 2

  # 3) 如果仍占用，按端口清理
  if ss -lptn 2>/dev/null | grep -E -q ":${port}\\b" || (command -v lsof >/dev/null 2>&1 && lsof -i :"$port" -sTCP:LISTEN >/dev/null 2>&1); then
    kill_by_port "$port"
  fi
}

status_service() {
  local svc="$1"
  local sname
  sname="$(session_name "$svc")"
  if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
  if exists_session "$sname"; then
    echo "[运行中] $svc -> '$sname'"
  else
    echo "[未运行] $svc"
  fi
}

attach_service() {
  local svc="$1"
  local sname
  sname="$(session_name "$svc")"
  if [[ -z "$sname" ]]; then echo "未知服务: $svc"; return 2; fi
  if exists_session "$sname"; then
    echo "附着到会话: $sname (退出: Ctrl+A 然后 D)"
    screen -r "$sname"
  else
    echo "服务未运行: $svc"
    return 1
  fi
}

start_all() {
  for s in "${SERVICE_NAMES[@]}"; do
    start_service "$s"
  done
}

stop_all() {
  for s in "${SERVICE_NAMES[@]}"; do
    stop_service "$s"
  done
}

status_all() {
  for s in "${SERVICE_NAMES[@]}"; do
    status_service "$s"
  done
}

restart_service() {
  local svc="$1"
  stop_service "$svc"
  # 等待会话释放
  sleep 1
  start_service "$svc"
}

usage() {
  cat <<EOF
用法: $0 <command> [service]

command:
  start [svc]     启动指定服务；不指定时启动全部
  stop [svc]      停止指定服务；不指定时停止全部
  restart [svc]   重启指定服务；不指定时重启全部
  status          查看所有服务状态
  attach <svc>    附着到指定服务的 screen 会话
  force-stop [svc] 强制结束进程（按端口终止）；不指定时对全部执行

service 可选值:
  intent | dify | answertype | qingdan
EOF
}

main() {
  local cmd="${1:-}"; shift || true
  case "$cmd" in
    start)
      local svc="${1:-all}"
      if [[ "$svc" == "all" ]]; then start_all; else start_service "$svc"; fi
      ;;
    stop)
      local svc="${1:-all}"
      if [[ "$svc" == "all" ]]; then stop_all; else stop_service "$svc"; fi
      ;;
    restart)
      local svc="${1:-all}"
      if [[ "$svc" == "all" ]]; then
        for s in "${SERVICE_NAMES[@]}"; do restart_service "$s"; done
      else
        restart_service "$svc"
      fi
      ;;
    status)
      status_all
      ;;
    attach)
      local svc="${1:-}"
      if [[ -z "$svc" ]]; then echo "请指定服务"; usage; exit 2; fi
      attach_service "$svc"
      ;;
    force-stop)
      local svc="${1:-all}"
      if [[ "$svc" == "all" ]]; then
        for s in "${SERVICE_NAMES[@]}"; do
          # 仅按端口强制清理
          p="$(service_port "$s")"
          if [[ -n "$p" ]]; then kill_by_port "$p"; fi
        done
      else
        local p
        p="$(service_port "$svc")"
        if [[ -z "$p" ]]; then echo "未知服务: $svc"; exit 2; fi
        kill_by_port "$p"
      fi
      ;;
    ""|-h|--help|help)
      usage
      ;;
    *)
      echo "未知命令: $cmd" >&2
      usage
      exit 2
      ;;
  esac
}

main "$@"
