#!/usr/bin/env sh
# RelayTerm Agent 安装器（Linux / macOS，每用户，不需要 sudo）
#
# 对应 Windows 那边的 i.ps1。装到 ~/.local/share/relayterm，注册为**当前用户**的
# 服务（systemd --user 或 launchd LaunchAgent），全程不碰系统目录、不改系统配置。
#
#   curl -fsSL https://www.made2020.cn/rt6k/releases/20261012/install.sh | sh
#   curl -fsSL https://www.made2020.cn/rt6k/releases/20261012/install.sh | sh -s -- --allow-exec
#
# 用法：
#   install.sh [--allow-exec] [--allow-delete] [--file-root DIR] [--owner NAME]
#   install.sh --status | --stop | --start | --uninstall
#
# ⚠️ 为什么坚持非 root：agent 的 --file-root 只约束文件传输，**完全不约束 exec**。
#    agent 以什么身份运行，控制端就有什么权限。用普通账号跑，影响范围才天然
#    局限在这个账号的文件上。绝不要用 sudo 运行本脚本。
set -eu

BASE_URL="${RELAYTERM_BASE_URL:-https://www.made2020.cn/rt6k/releases/20261012}"
RELAY_SERVER="${RELAYTERM_SERVER:-35.73.239.212:9090}"
CERT_PRINT="${RELAYTERM_CERT_FINGERPRINT:-bb5fbcc5bb44a70e0ae3c22eab232f430fadf84b5989a85f217147633503e56f}"

PREFIX="$HOME/.local/share/relayterm"
BIN_DIR="$HOME/.local/bin"
CONFIG="$HOME/.config/relayterm/agent.json"
LOG="$PREFIX/agent.log"

ALLOW_EXEC=""
ALLOW_DELETE=""
FILE_ROOT="$HOME/relayterm-work"
OWNER=""
ACTION="install"

while [ $# -gt 0 ]; do
  case "$1" in
    --allow-exec)   ALLOW_EXEC=1 ;;
    --allow-delete) ALLOW_DELETE=1 ;;
    --file-root)    FILE_ROOT="$2"; shift ;;
    --owner)        OWNER="$2"; shift ;;
    --status)       ACTION="status" ;;
    --stop)         ACTION="stop" ;;
    --start)        ACTION="start" ;;
    --uninstall)    ACTION="uninstall" ;;
    -h|--help)      sed -n '2,20p' "$0"; exit 0 ;;
    *) echo "未知参数: $1" >&2; exit 2 ;;
  esac
  shift
done

if [ "$(id -u)" = "0" ]; then
  echo "拒绝以 root 运行。用普通账号执行本脚本（见脚本顶部说明）。" >&2
  exit 1
fi

say()  { printf '\033[36m==>\033[0m %s\n' "$*"; }
ok()   { printf '\033[32m  ok\033[0m %s\n' "$*"; }
warn() { printf '\033[33m  !!\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[31m  xx\033[0m %s\n' "$*" >&2; exit 1; }

# --- 平台判定 ---------------------------------------------------------------
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
  Linux)  GOOS=linux ;;
  Darwin) GOOS=darwin ;;
  *) die "不支持的系统: $OS" ;;
esac
case "$ARCH" in
  x86_64|amd64)  GOARCH=amd64 ;;
  aarch64|arm64) GOARCH=arm64 ;;
  *) die "不支持的架构: $ARCH" ;;
esac

SERVICE_NAME="relayterm-agent"
SYSTEMD_UNIT="$HOME/.config/systemd/user/$SERVICE_NAME.service"
PLIST="$HOME/Library/LaunchAgents/com.relayterm.agent.plist"

svc_start() {
  if [ "$GOOS" = linux ]; then
    systemctl --user daemon-reload
    systemctl --user enable --now "$SERVICE_NAME.service"
  else
    launchctl unload "$PLIST" 2>/dev/null || true
    launchctl load "$PLIST"
  fi
}
svc_stop() {
  if [ "$GOOS" = linux ]; then
    systemctl --user disable --now "$SERVICE_NAME.service" 2>/dev/null || true
  else
    launchctl unload "$PLIST" 2>/dev/null || true
  fi
}
svc_status() {
  if [ "$GOOS" = linux ]; then
    systemctl --user status "$SERVICE_NAME.service" --no-pager || true
  else
    launchctl list | grep -i relayterm || echo "未注册"
  fi
}

case "$ACTION" in
  status)    svc_status; [ -f "$CONFIG" ] && { echo; echo "配置: $CONFIG"; cat "$CONFIG"; }; exit 0 ;;
  stop)      svc_stop; ok "已停止"; exit 0 ;;
  start)     svc_start; ok "已启动"; exit 0 ;;
  uninstall)
    svc_stop
    rm -f "$SYSTEMD_UNIT" "$PLIST"
    [ "$GOOS" = linux ] && systemctl --user daemon-reload 2>/dev/null || true
    rm -rf "$PREFIX"
    for c in relayterm-agent relayexec relaycp relaysync; do rm -f "$BIN_DIR/$c"; done
    warn "配置保留在 $CONFIG（含配对码，删了要重新配对）。确实要删就手动 rm。"
    ok "已卸载"
    exit 0 ;;
esac

# --- 下载 -------------------------------------------------------------------
say "平台 $GOOS/$GOARCH"
mkdir -p "$PREFIX" "$BIN_DIR" "$(dirname "$CONFIG")"
chmod 700 "$(dirname "$CONFIG")" 2>/dev/null || true

sha_of() {
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1
  else shasum -a 256 "$1" | cut -d' ' -f1; fi
}

TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

# --noproxy 是项目硬规则：系统代理设错会让下载静默走到别处
curl -fsSL --noproxy '*' --max-time 300 "$BASE_URL/SHA256SUMS-unix.txt" -o "$TMP/sums.txt" \
  || die "取校验和失败：$BASE_URL/SHA256SUMS-unix.txt"

for c in relayterm-agent relayexec relaycp relaysync; do
  name="$c-$GOOS-$GOARCH"
  say "下载 $name"
  curl -fsSL --noproxy '*' --max-time 600 "$BASE_URL/unix/$name" -o "$TMP/$c" || die "下载失败 $name"
  want="$(grep " $name\$" "$TMP/sums.txt" | cut -d' ' -f1 || true)"
  [ -n "$want" ] || die "$name 不在校验和清单里"
  got="$(sha_of "$TMP/$c")"
  [ "$want" = "$got" ] || die "$name 校验和不符：期望 $want 实得 $got"
  chmod 755 "$TMP/$c"
  mv "$TMP/$c" "$BIN_DIR/$c"
  ok "$name"
done

# --- 服务定义 ---------------------------------------------------------------
say "注册用户服务"
if [ "$GOOS" = linux ]; then
  mkdir -p "$(dirname "$SYSTEMD_UNIT")"
  cat > "$SYSTEMD_UNIT" <<EOF
[Unit]
Description=RelayTerm Go Agent (per-user)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.local/bin/relayterm-agent --config %h/.config/relayterm/agent.json
Restart=on-failure
RestartSec=5
NoNewPrivileges=true

[Install]
WantedBy=default.target
EOF
else
  mkdir -p "$(dirname "$PLIST")"
  cat > "$PLIST" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>com.relayterm.agent</string>
  <key>ProgramArguments</key><array>
    <string>$BIN_DIR/relayterm-agent</string>
    <string>--config</string><string>$CONFIG</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><true/>
  <key>StandardOutPath</key><string>$LOG</string>
  <key>StandardErrorPath</key><string>$LOG</string>
</dict></plist>
EOF
fi
ok "服务定义已写入"

# --- 首次配置 ---------------------------------------------------------------
# 配置文件里存着**配对码**。已存在就不动它 —— 重装不该让对端的配对失效。
mkdir -p "$FILE_ROOT"
[ -n "$OWNER" ] || OWNER="$GOOS-$(hostname 2>/dev/null || echo host)"

if [ -f "$CONFIG" ]; then
  say "已有配置，保留不动：$CONFIG"
  warn "要改策略请编辑该文件后 $0 --start，或先 --uninstall 再装。"
else
  say "生成配置"
  set -- --server "$RELAY_SERVER" --cert-fingerprint "$CERT_PRINT" \
         --owner "$OWNER" --file-root "$FILE_ROOT" --config "$CONFIG" --log-level info
  [ -n "$ALLOW_EXEC" ]   && set -- "$@" --allow-exec
  [ -n "$ALLOW_DELETE" ] && set -- "$@" --allow-delete
  # 跑一下让它把配置落盘并生成 machine_id / 配对码,然后立刻停掉,交给服务托管
  "$BIN_DIR/relayterm-agent" "$@" >"$LOG" 2>&1 &
  pid=$!
  sleep 4
  kill "$pid" 2>/dev/null || true
  wait "$pid" 2>/dev/null || true
  [ -f "$CONFIG" ] || die "配置没有生成，看日志：$LOG"
  chmod 600 "$CONFIG"
fi

svc_start
sleep 2

# --- 结果 -------------------------------------------------------------------
CODE="$(sed -n 's/.*"pairing_code"[ ]*:[ ]*"\([^"]*\)".*/\1/p' "$CONFIG" | head -1)"
MID="$(sed -n 's/.*"machine_id"[ ]*:[ ]*"\([^"]*\)".*/\1/p' "$CONFIG" | head -1)"
# 从**配置文件**读实际生效值,不要用命令行参数 —— 重装一台已开 exec 的机器时
# 没带 --allow-exec 的话,按参数打就会显示"未开启",而 agent 其实开着。
EXEC_ON="$(sed -n 's/.*"allow_exec"[ ]*:[ ]*\(true\|false\).*/\1/p' "$CONFIG" | head -1)"
ROOTS="$(sed -n 's/.*"file_roots"[ ]*:[ ]*\[[ ]*"\([^"]*\)".*/\1/p' "$CONFIG" | head -1)"

echo
echo "──────────────────────────────────────────────"
echo "  安装完成"
echo "──────────────────────────────────────────────"
echo "  配对码      : ${CODE:-?}"
echo "  machine_id  : ${MID:-?}"
echo "  中继服务器  : $RELAY_SERVER"
echo "  工作目录    : ${ROOTS:-$FILE_ROOT}   (文件传输只能进出这里)"
echo "  远程执行    : $([ "$EXEC_ON" = true ] && echo '已开启 —— 控制端可在本机执行命令' || echo '未开启（需要就先 --uninstall 再带 --allow-exec 装）')"
echo "  运行身份    : $(id -un)  (非 root)"
echo "  日志        : $LOG"
echo "──────────────────────────────────────────────"
echo "  状态: $0 --status    停止: $0 --stop"
echo

case ":$PATH:" in *":$BIN_DIR:"*) ;; *) warn "$BIN_DIR 不在 PATH 里，relaycp 等命令需要写全路径。" ;; esac
