#!/bin/bash
# ================================================================
# 🚀 SSR-Plus Docker 管理脚本（含 IPv4/IPv6 双栈增强 & 自动开启 Docker IPv6）
# 支持 Debian/Ubuntu/CentOS/RHEL/Rocky/AlmaLinux/Fedora/openSUSE
# 版本号: v1.3.0+ipv6
# 说明：
#  - 仅 IPv4 的机器 → 只发布/显示 IPv4；双栈 → 同时发布/显示。
#  - 自动：若检测到 Docker 未启用 IPv6，脚本会**自动配置 /etc/docker/daemon.json**，
#    开启 "ipv6": true 与 "fixed-cidr-v6"，并重启 Docker（需 root）。
#  - IPv6 ssr:// 链接建议使用域名（环境变量 SSRPLUS_IPV6_HOST）以保证兼容性。
# ================================================================

stty erase ^H   # 让退格键在终端里正常工作

DOCKER_IMAGE="yinqishuo/ssr:0.01"
CONTAINER_NAME="ssr"
CONFIG_PATH="/etc/shadowsocks-r/config.json"

# ========== 样式 ==========
RED='\e[31m'; GREEN='\e[32m'; YELLOW='\e[33m'; BLUE='\e[34m'; CYAN='\e[36m'; NC='\e[0m'
INDENT=" "
VERSION="v1.3.0+ipv6"

# ========== 更新源（可配镜像/IPv4/IPv6/强制覆盖）==========
RAW_URL_DEFAULT="https://raw.githubusercontent.com/Alvin9999/SSR-Plus/main/ssr-plus.sh"

# ========== 小工具 ==========
have_cmd(){ command -v "$1" >/dev/null 2>&1; }

# 当前脚本真实路径
script_path() {
  local p
  p="$(readlink -f "${BASH_SOURCE[0]:-$0}" 2>/dev/null || realpath "${BASH_SOURCE[0]:-$0}" 2>/dev/null || echo "$0")"
  if [[ ! -f "$p" || "$(basename "$p")" = "bash" ]]; then
    [[ -f "./ssr-plus.sh" ]] && p="./ssr-plus.sh" || { echo ""; return 1; }
  fi
  echo "$p"
}

# 标准 base64（单行）
enc_b64() {
  if have_cmd openssl; then
    printf '%s' "$1" | openssl enc -base64 -A
  else
    if base64 --help 2>/dev/null | grep -q -- '-w'; then
      printf '%s' "$1" | base64 -w0
    else
      printf '%s' "$1" | base64 | tr -d '\n'
    fi
  fi
}
# URL-safe base64（去 '='，将 '+/' → '-_'）
enc_b64url(){ enc_b64 "$1" | tr '+/' '-_' | tr -d '='; }

# 下载工具（支持 SSRPLUS_IPMODE=4/6、SSRPLUS_MIRROR）
fetch_to() {
  local url="$1" out="$2" opts=()
  [[ "$SSRPLUS_IPMODE" = "4" ]] && opts+=(-4)
  [[ "$SSRPLUS_IPMODE" = "6" ]] && opts+=(-6)
  if have_cmd curl; then
    curl -fsSL "${opts[@]}" "$url" -o "$out"
  else
    wget -q "${opts[@]}" -O "$out" "$url"
  fi
}

# ========== 系统检测 ==========
detect_os(){ if [ -f /etc/os-release ]; then . /etc/os-release; OS=$ID; else OS=$(uname -s); fi; }

# ========== Docker 安装 ==========
install_docker(){
  detect_os
  echo -e "${BLUE}${INDENT}[1/4] 安装 Docker... 系统: $OS${NC}"
  case "$OS" in
    ubuntu|debian)
      apt-get update -y
      apt-get install -y ca-certificates curl gnupg lsb-release
      mkdir -p /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/$OS/gpg | gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg
      echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS $(lsb_release -cs) stable" \
        | tee /etc/apt/sources.list.d/docker.list >/dev/null
      apt-get update -y
      apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
      ;;
    centos|rhel)
      yum install -y yum-utils device-mapper-persistent-data lvm2 || {
        echo -e "${RED}${INDENT}❌ yum-utils 安装失败，请先: yum clean all && rm -rf /var/cache/yum${NC}"; exit 1; }
      yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
      yum install -y docker-ce docker-ce-cli containerd.io || {
        echo -e "${RED}${INDENT}❌ Docker 安装失败，请检查网络/源${NC}"; exit 1; }
      ;;
    rocky|almalinux)
      dnf install -y dnf-plugins-core
      dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
      dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
      ;;
    fedora)
      dnf install -y dnf-plugins-core
      dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
      dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
      ;;
    opensuse*|sles)
      zypper install -y docker docker-runc
      ;;
    *)
      echo -e "${RED}${INDENT}⚠️ 未知系统，请手动安装 Docker${NC}"
      exit 1
      ;;
  esac
  command -v docker >/dev/null 2>&1 || { echo -e "${RED}${INDENT}❌ Docker 未安装成功${NC}"; exit 1; }
  systemctl enable docker >/dev/null 2>&1 || true
  systemctl start docker 2>/dev/null || service docker start 2>/dev/null || true
}

# ========== 确保 Docker 与 IPv6 ==========
ensure_docker_running(){ command -v docker >/dev/null 2>&1 || return 1; docker info >/dev/null 2>&1 || systemctl start docker 2>/dev/null || service docker start 2>/dev/null; docker info >/dev/null 2>&1; }

# 运行时及持久化开启内核 IPv6
ensure_kernel_ipv6_enabled(){
  local need=0
  if [[ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null)" = "1" ]]; then
    sysctl -w net.ipv6.conf.all.disable_ipv6=0 >/dev/null 2>&1 && need=1
  fi
  if [[ "$(cat /proc/sys/net/ipv6/conf/default/disable_ipv6 2>/dev/null)" = "1" ]]; then
    sysctl -w net.ipv6.conf.default.disable_ipv6=0 >/dev/null 2>&1 && need=1
  fi
  if ((need)); then
    mkdir -p /etc/sysctl.d
    cat >/etc/sysctl.d/99-ipv6-enable.conf <<'SYS'
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
SYS
    sysctl --system >/dev/null 2>&1 || sysctl -p >/dev/null 2>&1 || true
  fi
}

# Docker bridge 是否启用 IPv6
bridge_v6_enabled(){ docker network inspect bridge 2>/dev/null | grep -q '"EnableIPv6": *true'; }

# 自动开启 Docker IPv6（修改 /etc/docker/daemon.json 并重启）
ensure_docker_ipv6_auto(){
  command -v docker >/dev/null 2>&1 || return 0
  bridge_v6_enabled && return 0

  ensure_kernel_ipv6_enabled

  local daemon=/etc/docker/daemon.json; mkdir -p /etc/docker
  # 尝试准备 python3 以合并 JSON
  if ! have_cmd python3; then
    detect_os
    case "$OS" in
      ubuntu|debian) apt-get update -y && apt-get install -y python3 >/dev/null 2>&1 ;;
      centos|rhel) yum install -y python3 >/dev/null 2>&1 ;;
      rocky|almalinux|fedora) dnf install -y python3 >/dev/null 2>&1 ;;
      opensuse*|sles) zypper install -y python3 >/dev/null 2>&1 ;;
    esac
  fi
  local tmp; tmp="$(mktemp)"
  python3 - "$daemon" >"$tmp" <<'PY'
import json,sys,os
path=sys.argv[1]
data={}
if os.path.exists(path):
  try:
    with open(path,'r') as f:
      data=json.load(f)
  except Exception:
    pass
if data.get('ipv6') is not True:
  data['ipv6']=True
if not data.get('fixed-cidr-v6'):
  data['fixed-cidr-v6']='fd00:dead:beef::/48'
with open(path,'w') as f:
  json.dump(data,f,indent=2)
PY
  mv -f "$tmp" "$daemon"

  if have_cmd systemctl; then systemctl restart docker; else service docker restart 2>/dev/null || service docker start 2>/dev/null; fi
  for i in {1..10}; do docker info >/dev/null 2>&1 && break; sleep 1; done
  bridge_v6_enabled || echo -e "${YELLOW}${INDENT}⚠️ Docker IPv6 仍未启用（可稍后手动检查 daemon.json）${NC}"
}

# ========== 状态检测 ==========
check_ssr_status(){
  if ! command -v docker >/dev/null 2>&1; then SSR_STATUS="${RED}未安装 (Docker 未安装)${NC}"; return; fi
  docker info >/dev/null 2>&1 || { SSR_STATUS="${RED}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { SSR_STATUS="${RED}未安装${NC}"; return; }
  [ "$(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME 2>/dev/null)" = "true" ] || { SSR_STATUS="${YELLOW}容器已停止${NC}"; return; }
  if docker exec "$CONTAINER_NAME" pgrep -f "server.py" >/dev/null 2>&1; then
    SSR_STATUS="${GREEN}已启动${NC}"
  else
    SSR_STATUS="${YELLOW}容器运行中 (SSR 进程未运行)${NC}"
  fi
}

# ========== BBR 检测 ==========
check_bbr(){
  local cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null)
  local qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null)
  [[ "$cc" == "bbr" && "$qdisc" == "fq" ]] && BBR_STATUS="${GREEN}已启用 BBR${NC}" || BBR_STATUS="${RED}未启用 BBR${NC}"
}

# ========== 多 IP 收集（仅公网） ==========
MAX_V6_TO_SHOW=5

is_public_v4() {
  [[ "$1" =~ ^10\. ]] && return 1
  [[ "$1" =~ ^127\. ]] && return 1
  [[ "$1" =~ ^169\.254\. ]] && return 1
  [[ "$1" =~ ^192\.168\. ]] && return 1
  [[ "$1" =~ ^172\.(1[6-9]|2[0-9]|3[0-1])\. ]] && return 1
  [[ "$1" =~ ^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\. ]] && return 1
  [[ "$1" = "0.0.0.0" ]] && return 1
  return 0
}

get_ipv4_list() {
  local ips=()
  if have_cmd ip; then
    while IFS= read -r ip4; do
      is_public_v4 "$ip4" && ips+=("$ip4")
    done < <(ip -4 addr show scope global 2>/dev/null | awk '/inet /{print $2}' | cut -d/ -f1)
  else
    while IFS= read -r ip4; do
      [[ "$ip4" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] && is_public_v4 "$ip4" && ips+=("$ip4")
    done < <(hostname -I 2>/dev/null | tr ' ' '\n')
  fi
  printf '%s\n' "${ips[@]}"
}

# ---------- IPv6 能力探测与收集 ----------
ipv6_available() {
  [[ -f /proc/net/if_inet6 ]] && [[ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6 2>/dev/null)" != "1" ]]
}
# Docker bridge 是否启用 IPv6（避免 -p [::]:… 时报错）
docker_bridge_ipv6_enabled() { bridge_v6_enabled; }
# 过滤掉本地/链路本地/ULA 等非公网 v6
is_public_v6() {
  local ip="${1,,}"
  [[ "$ip" == "::1" ]] && return 1
  [[ "$ip" == fe80:* ]] && return 1
  [[ "$ip" == fc* || "$ip" == fd* ]] && return 1
  [[ "$ip" == :: ]] && return 1
  return 0
}
# 收集本机公网 IPv6 列表
get_ipv6_list() {
  local ips=()
  if command -v ip >/dev/null 2>&1; then
    while IFS= read -r ip6; do
      ip6="${ip6,,}"
      is_public_v6 "$ip6" && ips+=("$ip6")
    done < <(ip -6 addr show scope global 2>/dev/null | awk '/inet6 /{print $2}' | cut -d/ -f1)
  fi
  printf '%s\n' "${ips[@]}"
}

# ========== 可靠读取容器配置 ==========
read_config_vars() {
  local out
  out=$(docker exec -i "$CONTAINER_NAME" python - <<'PY'
import json,sys
p="/etc/shadowsocks-r/config.json"
try:
    with open(p,"r") as f:
        d=json.load(f)
    def esc(v):
        return (str(v) if v is not None else "").replace("\\","\\\\").replace("$","\\$").replace("`","\\`").replace('"','\\"')
    print('PORT="%s"' % esc(d.get("server_port","")))
    print('PASSWORD="%s"' % esc(d.get("password","")))
    print('METHOD="%s"' % esc(d.get("method","")))
    print('PROTOCOL="%s"' % esc(d.get("protocol","")))
    print('OBFS="%s"' % esc(d.get("obfs","")))
except Exception:
    pass
PY
  )
  eval "$out"
}

# ========== 选择项 ==========
choose_method(){ echo -e "\n${CYAN}${INDENT}请选择加密方式:${NC}"
  cat <<EOF
 ${INDENT}1) none
 ${INDENT}2) rc4
 ${INDENT}3) rc4-md5
 ${INDENT}4) rc4-md5-6
 ${INDENT}5) aes-128-ctr
 ${INDENT}6) aes-192-ctr
 ${INDENT}7) aes-256-ctr
 ${INDENT}8) aes-128-cfb
 ${INDENT}9) aes-192-cfb
 ${INDENT}10) aes-256-cfb
 ${INDENT}11) aes-128-cfb8
 ${INDENT}12) aes-192-cfb8
 ${INDENT}13) aes-256-cfb8
 ${INDENT}14) salsa20
 ${INDENT}15) chacha20
 ${INDENT}16) chacha20-ietf
EOF
  read -p "${INDENT}输入序号 [默认16]: " method
  case $method in
    1) METHOD="none";; 2) METHOD="rc4";; 3) METHOD="rc4-md5";; 4) METHOD="rc4-md5-6";;
    5) METHOD="aes-128-ctr";; 6) METHOD="aes-192-ctr";; 7) METHOD="aes-256-ctr";;
    8) METHOD="aes-128-cfb";; 9) METHOD="aes-192-cfb";; 10) METHOD="aes-256-cfb";;
    11) METHOD="aes-128-cfb8";; 12) METHOD="aes-192-cfb8";; 13) METHOD="aes-256-cfb8";;
    14) METHOD="salsa20";; 15) METHOD="chacha20";; 16|"") METHOD="chacha20-ietf";; *) METHOD="chacha20-ietf";;
  esac
}
choose_protocol(){ echo -e "\n${CYAN}${INDENT}请选择协议 (protocol):${NC}"
  cat <<EOF
 ${INDENT}1) origin
 ${INDENT}2) auth_sha1_v4
 ${INDENT}3) auth_aes128_md5
 ${INDENT}4) auth_aes128_sha1
 ${INDENT}5) auth_chain_a
 ${INDENT}6) auth_chain_b
EOF
  read -p "${INDENT}输入序号 [默认2]: " protocol
  case $protocol in
    1) PROTOCOL="origin";; 2|"") PROTOCOL="auth_sha1_v4";; 3) PROTOCOL="auth_aes128_md5";;
    4) PROTOCOL="auth_aes128_sha1";; 5) PROTOCOL="auth_chain_a";; 6) PROTOCOL="auth_chain_b";; *) PROTOCOL="auth_sha1_v4";;
  esac
}
choose_obfs(){ echo -e "\n${CYAN}${INDENT}请选择混淆 (obfs):${NC}"
  cat <<EOF
 ${INDENT}1) plain
 ${INDENT}2) http_simple
 ${INDENT}3) http_post
 ${INDENT}4) random_head
 ${INDENT}5) tls1.2_ticket_auth
EOF
  read -p "${INDENT}输入序号 [默认1]: " obfs
  case $obfs in
    1|"") OBFS="plain";; 2) OBFS="http_simple";; 3) OBFS="http_post";; 4) OBFS="random_head";; 5) OBFS="tls1.2_ticket_auth";; *) OBFS="plain";;
  esac
}

# ========== 配置（原子写入） ==========
set_config(){
  docker exec -i $CONTAINER_NAME bash -lc "umask 077; mkdir -p /etc/shadowsocks-r && cat > ${CONFIG_PATH}.tmp && mv -f ${CONFIG_PATH}.tmp ${CONFIG_PATH} && sync" <<EOF
{
  "server":"0.0.0.0",
  "server_ipv6":"::",
  "server_port":${PORT},
  "local_address":"127.0.0.1",
  "local_port":1080,
  "password":"${PASSWORD}",
  "timeout":120,
  "method":"${METHOD}",
  "protocol":"${PROTOCOL}",
  "protocol_param":"",
  "obfs":"${OBFS}",
  "obfs_param":"",
  "redirect":"",
  "dns_ipv6":false,
  "fast_open":false,
  "workers":1
}
EOF
}

# ========== 链接与配置展示（IPv4/IPv6） ==========
generate_ssr_link() {
  read_config_vars
  local v4s=() v6s=()
  mapfile -t v4s < <(get_ipv4_list)
  mapfile -t v6s < <(get_ipv6_list)

  local pwd_b64url remarks_b64url group_b64url
  pwd_b64url="$(enc_b64url "$PASSWORD")"
  group_b64url="$(enc_b64url "SSR-Plus")"

  echo -e "\n${GREEN}${INDENT}SSR 链接（按需导入）：${NC}"

  if ((${#v4s[@]})); then
    for ip4 in "${v4s[@]}"; do
      remarks_b64url="$(enc_b64url "SSR-Plus:[IPv4] ${ip4}:${PORT}")"
      local raw="${ip4}:${PORT}:${PROTOCOL}:${METHOD}:${OBFS}:${pwd_b64url}/?obfsparam=&protoparam=&remarks=${remarks_b64url}&group=${group_b64url}"
      echo -e "${INDENT}- ${YELLOW}[IPv4] ${ip4}${NC}: ssr://$(enc_b64url "$raw")"
    done
  else
    echo -e "${INDENT}- ${YELLOW}[IPv4] 未检测到公网 IPv4${NC}"
  fi

  if ((${#v6s[@]})); then
    if [[ -n "$SSRPLUS_IPV6_HOST" ]]; then
      local host="$SSRPLUS_IPV6_HOST"
      remarks_b64url="$(enc_b64url "SSR-Plus:[IPv6] ${host}:${PORT}")"
      local raw6="${host}:${PORT}:${PROTOCOL}:${METHOD}:${OBFS}:${pwd_b64url}/?obfsparam=&protoparam=&remarks=${remarks_b64url}&group=${group_b64url}"
      echo -e "${INDENT}- ${YELLOW}[IPv6] ${host}${NC}: ssr://$(enc_b64url "$raw6")"
    else
      local shown=0
      for ip6 in "${v6s[@]}"; do
        echo -e "${INDENT}- ${YELLOW}[IPv6] ${ip6}${NC}: （未设置 SSRPLUS_IPV6_HOST，无法生成通用 ssr:// 链接；建议使用带 AAAA 记录的域名）"
        ((shown++>=2)) && break
      done
    fi
  fi
  echo
}

show_config() {
  command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1 || { echo -e "${RED}${INDENT}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { echo -e "${RED}${INDENT}未检测到 SSR 容器${NC}"; return; }
  docker exec "$CONTAINER_NAME" test -f "$CONFIG_PATH" || { echo -e "${YELLOW}${INDENT}容器内未找到配置文件${NC}"; return; }

  read_config_vars

  local v4_list v6_list
  v4_list=$(get_ipv4_list | paste -sd, -)
  v6_list=$(get_ipv6_list | head -n ${MAX_V6_TO_SHOW:-5} | paste -sd, -)

  echo -e "${CYAN}${INDENT}===== 当前 SSR 配置 =====${NC}"
  echo -e "${INDENT}🌐 IPv4     : ${YELLOW}${v4_list:-无}${NC}"
  echo -e "${INDENT}🌐 IPv6     : ${YELLOW}${v6_list:-无}${NC}"
  echo -e "${INDENT}🔌 端口     : ${YELLOW}${PORT}${NC}"
  echo -e "${INDENT}🔑 密码     : ${YELLOW}${PASSWORD}${NC}"
  echo -e "${INDENT}🔒 加密方式 : ${YELLOW}${METHOD}${NC}"
  echo -e "${INDENT}📜 协议     : ${YELLOW}${PROTOCOL}${NC}"
  echo -e "${INDENT}🎭 混淆     : ${YELLOW}${OBFS}${NC}"
  echo -e "${CYAN}${INDENT}=========================${NC}"

  generate_ssr_link
}

# ========== 启动等待 & 重试 ==========
start_ssr_and_wait(){
  docker exec -d "$CONTAINER_NAME" python /usr/local/shadowsocks/server.py -c "$CONFIG_PATH" -d start
  for i in {1..5}; do
    sleep 1
    docker exec "$CONTAINER_NAME" pgrep -f "server.py" >/dev/null 2>&1 && { echo -e "${GREEN}${INDENT}✅ SSR 已启动${NC}"; return 0; }
  done
  docker exec -d "$CONTAINER_NAME" python /usr/local/shadowsocks/server.py -c "$CONFIG_PATH" -d start
  sleep 1
  docker exec "$CONTAINER_NAME" pgrep -f "server.py" >/dev/null 2>&1 && { echo -e "${GREEN}${INDENT}✅ SSR 已启动${NC}"; return 0; }
  echo -e "${RED}${INDENT}❌ SSR 启动失败，最近日志：${NC}"
  docker logs --tail 80 "$CONTAINER_NAME" 2>&1 | sed "s/^/${INDENT}/"
  return 1
}

# ========== 生成容器（带自启守护脚本） ==========
run_container_with_boot(){
  local map_port="$1"

  local port_flags=( -p "${map_port}:${map_port}" )
  if ipv6_available && docker_bridge_ipv6_enabled; then
    port_flags+=( -p "[::]:${map_port}:${map_port}" )
  else
    [[ -n "$INDENT" ]] && echo -e "${YELLOW}${INDENT}提示：未检测到 Docker IPv6（或宿主未启用），跳过 IPv6 端口发布${NC}"
  fi

  # 用 ANSI-C 字面量安全注入换行，避免 heredoc 被破坏
  local payload=$'cat >/usr/local/bin/ssr-boot.sh << "SH"\n#!/bin/bash\nCFG="/etc/shadowsocks-r/config.json"\n# 等待配置写入\nfor i in {1..60}; do [ -f "$CFG" ] && break; sleep 1; done\nsleep 2\npgrep -f server.py >/dev/null 2>&1 || python /usr/local/shadowsocks/server.py -c "$CFG" -d start\nwhile sleep 5; do\n  pgrep -f server.py >/dev/null 2>&1 || python /usr/local/shadowsocks/server.py -c "$CFG" -d start\n done\nSH\nchmod +x /usr/local/bin/ssr-boot.sh\nexec /usr/local/bin/ssr-boot.sh'

  docker run -dit --name "$CONTAINER_NAME" \
    --restart unless-stopped \
    "${port_flags[@]}" \
    --health-cmd "python -c 'import socket,sys; s=socket.socket(); s.settimeout(2); s.connect((\"127.0.0.1\",${map_port})); s.close()' || exit 1" \
    --health-interval 10s --health-retries 3 --health-timeout 3s --health-start-period 5s \
    "$DOCKER_IMAGE" \
    bash -lc "$payload"
}

# ========== 功能 ==========
install_ssr(){
  echo -e "${BLUE}${INDENT}安装 SSR...${NC}"
  read -p "${INDENT}请输入端口 [默认20000]: " PORT; PORT=${PORT:-20000}
  read -p "${INDENT}请输入密码 [默认dongtaiwang.com]: " PASSWORD; PASSWORD=${PASSWORD:-dongtaiwang.com}
  choose_method; choose_protocol; choose_obfs

  install_docker; ensure_docker_running || { echo -e "${RED}${INDENT}Docker 未运行，安装中止${NC}"; return; }
  ensure_docker_ipv6_auto   # << 自动开启 Docker IPv6
  docker pull $DOCKER_IMAGE
  docker stop $CONTAINER_NAME >/dev/null 2>&1; docker rm $CONTAINER_NAME >/dev/null 2>&1

  run_container_with_boot "${PORT}"
  sleep 1
  set_config
  start_ssr_and_wait
  echo -e "${GREEN}${INDENT}✅ SSR 安装完成${NC}"
  show_config
}

change_config(){
  ensure_docker_running || { echo -e "${RED}${INDENT}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { echo -e "${RED}${INDENT}未检测到 SSR 容器${NC}"; return; }

  echo -e "${BLUE}${INDENT}修改 SSR 配置...${NC}"
  if docker exec "$CONTAINER_NAME" test -f "$CONFIG_PATH"; then
    read_config_vars
  fi

  read -p "${INDENT}新端口 (回车保留: ${PORT:-20000}): " NEW_PORT
  read -p "${INDENT}新密码 (回车保留: ${PASSWORD:-dongtaiwang.com}): " NEW_PASSWORD
  choose_method; choose_protocol; choose_obfs
  NEW_PORT=${NEW_PORT:-$PORT}; PASSWORD=${NEW_PASSWORD:-$PASSWORD}

  ensure_docker_ipv6_auto   # << 自动开启 Docker IPv6

  if [ "$NEW_PORT" != "$PORT" ] && [ -n "$NEW_PORT" ]; then
    echo -e "${YELLOW}${INDENT}端口改变，重新创建容器...${NC}"
    docker stop $CONTAINER_NAME >/dev/null 2>&1; docker rm $CONTAINER_NAME >/dev/null 2>&1
    run_container_with_boot "${NEW_PORT}"
    sleep 1
  fi

  PORT=${NEW_PORT:-$PORT}
  set_config
  docker exec -d $CONTAINER_NAME python /usr/local/shadowsocks/server.py -c $CONFIG_PATH -d stop >/dev/null 2>&1
  sleep 1
  start_ssr_and_wait
  echo -e "${GREEN}${INDENT}✅ 配置修改完成${NC}"
  show_config
}

start_ssr(){
  ensure_docker_running || { echo -e "${RED}${INDENT}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { echo -e "${RED}${INDENT}未检测到 SSR 容器${NC}"; return; }
  [ "$(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME 2>/dev/null)" = "true" ] || docker start "$CONTAINER_NAME" >/dev/null 2>&1
  docker exec "$CONTAINER_NAME" test -f "$CONFIG_PATH" || { echo -e "${YELLOW}${INDENT}未发现配置文件${NC}"; return; }
  start_ssr_and_wait
}

stop_ssr(){
  ensure_docker_running || { echo -e "${RED}${INDENT}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { echo -e "${RED}${INDENT}未检测到 SSR 容器${NC}"; return; }
  [ "$(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME 2>/dev/null)" = "true" ] && docker exec -d "$CONTAINER_NAME" python /usr/local/shadowsocks/server.py -c "$CONFIG_PATH" -d stop
  sleep 1
  docker exec "$CONTAINER_NAME" pgrep -f "server.py" >/dev/null 2>&1 && echo -e "${RED}${INDENT}❌ SSR 停止失败${NC}" || echo -e "${YELLOW}${INDENT}🛑 SSR 已停止${NC}"
}

restart_ssr(){
  ensure_docker_running || { echo -e "${RED}${INDENT}Docker 未运行${NC}"; return; }
  docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || { echo -e "${RED}${INDENT}未检测到 SSR 容器${NC}"; return; }
  [ "$(docker inspect -f '{{.State.Running}}' $CONTAINER_NAME 2>/dev/null)" = "true" ] || docker start "$CONTAINER_NAME" >/dev/null 2>&1
  docker exec "$CONTAINER_NAME" test -f "$CONFIG_PATH" || { echo -e "${YELLOW}${INDENT}未发现配置文件${NC}"; return; }
  docker exec -d "$CONTAINER_NAME" python /usr/local/shadowsocks/server.py -c "$CONFIG_PATH" -d stop
  sleep 1; start_ssr_and_wait; echo -e "${GREEN}${INDENT}🔄 SSR 已重启${NC}"
}

uninstall_ssr(){
  echo -e "${RED}${INDENT}卸载 SSR...${NC}"
  if command -v docker >/dev/null 2>&1; then docker stop $CONTAINER_NAME >/dev/null 2>&1; docker rm $CONTAINER_NAME >/dev/null 2>&1; docker rmi $DOCKER_IMAGE >/dev/null 2>&1; fi
  echo -e "${RED}${INDENT}✅ SSR 已卸载完成${NC}"
}

# ========== 系统加速 ==========
optimize_system(){
  echo -e "${BLUE}${INDENT}检查系统加速状态...${NC}"
  local cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null); local qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null)
  if [[ "$cc" == "bbr" && "$qdisc" == "fq" ]]; then
    echo -e "${GREEN}${INDENT}✅ 系统加速已启用 (BBR + TFO)${NC}"
  else
    echo -e "${YELLOW}${INDENT}正在启用 TCP Fast Open + BBR...${NC}"
    { echo "net.ipv4.tcp_fastopen = 3"; echo "net.core.default_qdisc = fq"; echo "net.ipv4.tcp_congestion_control = bbr"; } >> /etc/sysctl.conf
    sysctl -p >/dev/null 2>&1
    cc=$(sysctl -n net.ipv4.tcp_congestion_control 2>/dev/null); qdisc=$(sysctl -n net.core.default_qdisc 2>/dev/null)
    [[ "$cc" == "bbr" && "$qdisc" == "fq" ]] && echo -e "${GREEN}${INDENT}✅ 系统加速已成功启用 (BBR + TCP Fast Open)${NC}" \
                                            || echo -e "${RED}${INDENT}⚠️ 内核可能不支持 BBR (>=4.9)${NC}"
  fi
}

# ========== 自愈（保留） ==========
auto_heal_ssr(){
  command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1 || return
  docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$" || return
  docker exec "$CONTAINER_NAME" pgrep -f "server.py" >/dev/null 2>&1 && return
  echo -e "${YELLOW}${INDENT}检测到 SSR 未运行，尝试自动拉起...${NC}"
  start_ssr_and_wait
}

# ========== 脚本自更新 ==========
update_script() {
  echo -e "${BLUE}${INDENT}检查脚本更新...${NC}"
  local raw="${RAW_URL_DEFAULT}"
  [[ -n "$SSRPLUS_MIRROR" ]] && raw="${SSRPLUS_MIRROR}${RAW_URL_DEFAULT}"

  local tmp="$(mktemp)"
  if ! fetch_to "$raw" "$tmp"; then
    echo -e "${RED}${INDENT}❌ 下载失败。${NC}"
    echo -e "${YELLOW}${INDENT}可设置镜像： export SSRPLUS_MIRROR='https://ghproxy.com/'${NC}"
    echo -e "${YELLOW}${INDENT}切换 IPv4/IPv6： export SSRPLUS_IPMODE=4  或  6${NC}"
    rm -f "$tmp"; return 1
  fi
  if ! grep -q "SSR-Plus Docker 管理脚本" "$tmp"; then
    echo -e "${RED}${INDENT}❌ 下载内容异常，已取消更新${NC}"; rm -f "$tmp"; return 1
  fi

  local self; self="$(script_path)"
  if [[ -z "$self" ]]; then
    echo -e "${RED}${INDENT}❌ 无法定位当前脚本路径，请在脚本所在目录执行更新${NC}"
    rm -f "$tmp"; return 1
  fi

  local local_ver remote_ver
  local_ver="$(grep -E 'VERSION="' "$self" 2>/dev/null | head -n1 | sed -E 's/.*VERSION="([^"]+)".*/\1/')"
  remote_ver="$(grep -E 'VERSION="' "$tmp"  2>/dev/null | head -n1 | sed -E 's/.*VERSION="([^"]+)".*/\1/')"
  [[ -z "$local_ver" ]] && local_ver="v0.0.0"
  [[ -z "$remote_ver" ]] && { echo -e "${RED}${INDENT}❌ 未能解析远端版本号，已取消更新${NC}"; rm -f "$tmp"; return 1; }

  local lv rv max; lv="${local_ver#v}"; rv="${remote_ver#v}"
  max="$(printf '%s\n%s\n' "$lv" "$rv" | sort -V | tail -n1)"

  if [[ "$lv" = "$rv" && "$SSRPLUS_FORCE" != "1" ]]; then
    echo -e "${GREEN}${INDENT}✅ 已是最新版：${local_ver}${NC}"
    echo -e "${INDENT}如需强制覆盖，请： export SSRPLUS_FORCE=1  后再执行更新。"
    rm -f "$tmp"; return 0
  fi
  if [[ "$max" = "$lv" && "$lv" != "$rv" && "$SSRPLUS_FORCE" != "1" ]]; then
    echo -e "${YELLOW}${INDENT}ℹ️ 本地版本 (${local_ver}) 新于远端 (${remote_ver})，跳过更新${NC}"
    echo -e "${INDENT}如需覆盖远端版本，可： export SSRPLUS_FORCE=1  后再执行更新。"
    rm -f "$tmp"; return 0
  fi

  cp -f "$self" "$self.bak-$(date +%F-%H%M%S)" 2>/dev/null
  chmod +x "$tmp" && mv -f "$tmp" "$self"
  echo -e "${GREEN}${INDENT}✅ 更新完成： ${local_ver} → ${remote_ver}${NC}"
  echo -e "${INDENT}正在重新加载新版本..."
  exec bash "$self"
}

# ========== 主菜单 ==========
check_bbr
ensure_docker_running >/dev/null 2>&1
ensure_docker_ipv6_auto >/dev/null 2>&1
check_ssr_status
auto_heal_ssr
check_ssr_status

echo -e "${CYAN}${INDENT}=============================="
echo -e "${INDENT}🚀 SSR-Plus 管理脚本 ${VERSION} 🚀"
echo -e "${INDENT}脚本更新地址:https://github.com/Alvin9999/SSR-Plus"
echo -e "${INDENT}==============================${NC}"
echo -e "${GREEN}${INDENT}1) 安装 SSR${NC}"
echo -e "${GREEN}${INDENT}2) 修改配置${NC}"
echo -e "${GREEN}${INDENT}3) 查看配置${NC}"
echo -e "${GREEN}${INDENT}4) 启动 SSR${NC}"
echo -e "${GREEN}${INDENT}5) 停止 SSR${NC}"
echo -e "${GREEN}${INDENT}6) 重启 SSR${NC}"
echo -e "${YELLOW}${INDENT}7) 卸载 SSR${NC}"
echo -e "${BLUE}${INDENT}8) 启用系统加速 (BBR + TFO)${NC}"
echo -e "${BLUE}${INDENT}9) 检查并更新脚本${NC}"
echo -e "${RED}${INDENT}10) 退出${NC}"
echo -e "${CYAN}${INDENT}==============================${NC}"
echo -e "${INDENT}系统加速状态: ${BBR_STATUS}"
echo -e "${INDENT}SSR 当前状态: ${SSR_STATUS}"
echo -e "${CYAN}${INDENT}==============================${NC}"

read -p "${INDENT}请输入选项 [1-10]: " choice
case $choice in
  1) install_docker; install_ssr ;;
  2) change_config ;;
  3) show_config ;;
  4) start_ssr ;;
  5) stop_ssr ;;
  6) restart_ssr ;;
  7) uninstall_ssr ;;
  8) optimize_system ;;
  9) update_script ;;
  10) exit 0 ;;
  *) echo -e "${RED}${INDENT}无效选项${NC}";;
esac
