#!/bin/bash
# 在另一台 Linux 服务器上安装 IP 守护面板。
# 用法：
#   bash install.sh https://api-cf.ladder-cat.com/cf-ip-guard.tar.gz
#   bash install.sh /root/cf-ip-guard.tar.gz
#   bash install.sh --port 12580 https://api-cf.ladder-cat.com/cf-ip-guard.tar.gz
set -euo pipefail

HOST_BIND="0.0.0.0"
PORT="12580"
PORT_SET="0"
TARBALL=""

usage() {
  echo "用法：bash install.sh [--port 12580] <安装包.tar.gz 或网址>"
  exit 1
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --port)
      PORT="${2:-}"
      PORT_SET="1"
      shift 2
      ;;
    --host)
      HOST_BIND="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      ;;
    *)
      TARBALL="$1"
      shift
      ;;
  esac
done

if [ "$(id -u)" -ne 0 ]; then
  echo "请用 root 运行。"
  exit 1
fi

if ! [[ "$PORT" =~ ^[0-9]+$ ]] || [ "$PORT" -lt 1 ] || [ "$PORT" -gt 65535 ]; then
  echo "端口不正确：$PORT"
  exit 1
fi

download() {
  local url="$1"
  local output="$2"
  if command -v curl >/dev/null 2>&1; then
    curl -fL --retry 3 --connect-timeout 20 -A "cf-ip-guard-installer" -o "$output" "$url"
  elif command -v wget >/dev/null 2>&1; then
    wget -O "$output" "$url"
  else
    echo "系统里没有 curl 或 wget。"
    exit 1
  fi
}

if [ -z "$TARBALL" ]; then
  script_dir=$(cd "$(dirname "$0")" && pwd)
  if [ -f "$script_dir/cf-ip-guard.tar.gz" ]; then
    TARBALL="$script_dir/cf-ip-guard.tar.gz"
  else
    usage
  fi
fi

work=$(mktemp -d)
cleanup() { rm -rf "$work"; }
trap cleanup EXIT

if [[ "$TARBALL" == http://* || "$TARBALL" == https://* ]]; then
  echo "正在下载安装包…"
  download "$TARBALL" "$work/cf-ip-guard.tar.gz"
  package="$work/cf-ip-guard.tar.gz"
  base="${TARBALL%/*}"
  download "$base/SHA256SUMS" "$work/SHA256SUMS" || true
else
  if [ ! -f "$TARBALL" ]; then
    echo "找不到安装包：$TARBALL"
    exit 1
  fi
  package="$TARBALL"
  sums_beside="$(dirname "$package")/SHA256SUMS"
  if [ -f "$sums_beside" ]; then
    cp "$sums_beside" "$work/SHA256SUMS"
  fi
fi

if [ -f "$work/SHA256SUMS" ]; then
  actual=$(sha256sum "$package" | awk '{print $1}')
  expect=$(awk 'NF { print $1; exit }' "$work/SHA256SUMS")
  if [ -n "$expect" ] && [ "$actual" != "$expect" ]; then
    echo "安装包校验失败。"
    echo "期望 $expect"
    echo "实际 $actual"
    exit 1
  fi
  echo "安装包校验通过。"
else
  echo "没有找到 SHA256SUMS，跳过校验。"
fi

if ! command -v tar >/dev/null 2>&1 || ! command -v curl >/dev/null 2>&1; then
  if command -v apt-get >/dev/null 2>&1; then
    apt-get update -y
    apt-get install -y ca-certificates curl tar
  elif command -v dnf >/dev/null 2>&1; then
    dnf install -y ca-certificates curl tar
  elif command -v yum >/dev/null 2>&1; then
    yum install -y ca-certificates curl tar
  fi
fi

tar -xzf "$package" -C "$work"
if [ -f "$work/server.js" ]; then
  source_dir="$work"
elif [ -f "$work/cf-ip-guard/server.js" ]; then
  source_dir="$work/cf-ip-guard"
else
  echo "压缩包里没有面板程序。"
  exit 1
fi

mkdir -p /opt/cf-ip-guard/data
if [ ! -f /opt/cf-ip-guard/data/settings.json ] && [ -f "$source_dir/seed/settings.json" ]; then
  cp -a "$source_dir/seed/settings.json" /opt/cf-ip-guard/data/settings.json
  chmod 600 /opt/cf-ip-guard/data/settings.json
  echo "已写入安装包里的面板设置。"
fi
shopt -s dotglob
for item in "$source_dir"/*; do
  base_name=$(basename "$item")
  if [ "$base_name" = "data" ] || [ "$base_name" = "dist" ]; then
    continue
  fi
  cp -a "$item" /opt/cf-ip-guard/
done
shopt -u dotglob
if [ -f /opt/cf-ip-guard/seed/settings.json ]; then
  chmod 700 /opt/cf-ip-guard/seed
  chmod 600 /opt/cf-ip-guard/seed/settings.json
fi

pick_node() {
  if command -v node >/dev/null 2>&1; then
    major=$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo 0)
    if [ "${major:-0}" -ge 18 ]; then
      command -v node
      return 0
    fi
  fi
  return 1
}

install_node() {
  echo "系统 Node 低于 18，正在安装独立运行时…" >&2
  local index="$work/index.json"
  if ! download "https://npmmirror.com/mirrors/node/index.json" "$index"; then
    download "https://nodejs.org/dist/index.json" "$index"
  fi
  local ver
  ver=$(grep -o '"version":"v22\.[0-9][0-9.]*"' "$index" | head -n 1 | sed 's/.*"version":"//;s/"//')
  if [ -z "$ver" ]; then
    ver=$(grep -o '"version":"v[0-9][0-9.]*"' "$index" | head -n 1 | sed 's/.*"version":"//;s/"//')
  fi
  if [ -z "$ver" ]; then
    echo "无法确定 Node 版本。" >&2
    exit 1
  fi
  local arch
  case "$(uname -m)" in
    x86_64|amd64) arch="x64" ;;
    aarch64|arm64) arch="arm64" ;;
    *)
      echo "不支持的系统架构：$(uname -m)" >&2
      exit 1
      ;;
  esac
  local file="node-${ver}-linux-${arch}.tar.gz"
  local archive="$work/$file"
  if ! download "https://npmmirror.com/mirrors/node/${ver}/${file}" "$archive"; then
    download "https://nodejs.org/dist/${ver}/${file}" "$archive"
  fi
  mkdir -p /opt/cf-ip-guard/runtime
  tar -xzf "$archive" -C /opt/cf-ip-guard/runtime --strip-components=1
  if ! /opt/cf-ip-guard/runtime/bin/node -v >/dev/null 2>&1; then
    echo "Node 无法在这台系统上运行。请换 Ubuntu 20.04、Debian 11 或更新的系统，或先自行安装 Node 18 以上。" >&2
    exit 1
  fi
}

if NODE_BIN=$(pick_node); then
  echo "使用已安装的 Node：$NODE_BIN" >&2
else
  install_node
  NODE_BIN=/opt/cf-ip-guard/runtime/bin/node
fi
case "$NODE_BIN" in
  /*) ;;
  *)
    echo "Node 路径不正确：$NODE_BIN" >&2
    exit 1
    ;;
esac
if [ ! -x "$NODE_BIN" ]; then
  echo "Node 不能执行：$NODE_BIN" >&2
  exit 1
fi

if ! id ipguard >/dev/null 2>&1; then
  useradd --system --home-dir /opt/cf-ip-guard --shell /usr/sbin/nologin ipguard \
    || useradd --system --home-dir /opt/cf-ip-guard --shell /sbin/nologin ipguard
fi

if [ ! -f /etc/cf-ip-guard.env ]; then
  cat > /etc/cf-ip-guard.env <<EOF
IPGUARD_HOST=${HOST_BIND}
IPGUARD_PORT=${PORT}
IPGUARD_DATA=/opt/cf-ip-guard/data
EOF
fi

if [ "$PORT_SET" = "1" ]; then
  if grep -q '^IPGUARD_PORT=' /etc/cf-ip-guard.env; then
    sed -i.bak "s/^IPGUARD_PORT=.*/IPGUARD_PORT=${PORT}/" /etc/cf-ip-guard.env
    rm -f /etc/cf-ip-guard.env.bak
  else
    echo "IPGUARD_PORT=${PORT}" >> /etc/cf-ip-guard.env
  fi
fi

chmod 644 /etc/cf-ip-guard.env
chown -R ipguard:ipguard /opt/cf-ip-guard
chmod 700 /opt/cf-ip-guard/data

cat > /opt/cf-ip-guard/start.sh <<EOF
#!/bin/sh
exec "$NODE_BIN" /opt/cf-ip-guard/server.js >> /var/log/cf-ip-guard.log 2>&1
EOF
chmod 755 /opt/cf-ip-guard/start.sh
touch /var/log/cf-ip-guard.log
chmod 640 /var/log/cf-ip-guard.log
chown ipguard:ipguard /opt/cf-ip-guard/start.sh /var/log/cf-ip-guard.log

cat > /etc/systemd/system/cf-ip-guard.service <<EOF
[Unit]
Description=IP 守护面板
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=ipguard
Group=ipguard
WorkingDirectory=/opt/cf-ip-guard
EnvironmentFile=/etc/cf-ip-guard.env
ExecStart=/opt/cf-ip-guard/start.sh
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable cf-ip-guard >/dev/null
systemctl restart cf-ip-guard || true
ready=0
for _ in 1 2 3 4 5; do
  if systemctl is-active --quiet cf-ip-guard; then
    ready=1
    break
  fi
  sleep 1
done

if [ "$ready" != "1" ]; then
  echo "面板没有启动。日志："
  tail -n 40 /var/log/cf-ip-guard.log || true
  systemctl status cf-ip-guard --no-pager -l || true
  exit 1
fi

if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
  firewall-cmd --permanent --add-port="${PORT}/tcp" >/dev/null || true
  firewall-cmd --reload >/dev/null || true
  echo "已在 firewalld 放行 ${PORT}/tcp。"
fi

if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
  ufw allow "${PORT}/tcp" >/dev/null || true
  echo "已在 ufw 放行 ${PORT}/tcp。"
fi

echo
echo "安装完成。"
echo "本机访问：http://127.0.0.1:${PORT}"
public_ip=$(curl -fsSL --max-time 5 https://api.ipify.org || true)
if [ -n "$public_ip" ]; then
  echo "外网访问：http://${public_ip}:${PORT}"
fi
echo "默认管理员密码是 admin。登录后可以在设置里修改。"
echo "云服务器安全组和宝塔防火墙也要放行 ${PORT}/tcp。"
echo "查看日志：journalctl -u cf-ip-guard -f"
echo "修改端口：编辑 /etc/cf-ip-guard.env 后执行 systemctl restart cf-ip-guard"
