#!/usr/bin/env bash
# dsh device-agent 一键安装（M1-C T1.1 + M1-D T2.1 隧道编排）
# 职责：安装 Node 24+ / @deepseek-ai/dsh 锁版 / frpc；初始化 $DSH_HOME；写入 --trusted-host 启动参数；
#       设备注册后生成 frpc.toml 并注册 frpc 守护（launchd/systemd）。
# 用法：
#   ./install.sh [--control-plane https://dsh.yjsm.shop] [--dsh-version 0.1.0-rc.6] [--frp-token xxx] [--skip-daemon]
#   一键安装(未装 Harness 的新电脑):curl -fsSL https://dsh.yjsm.shop/install.sh | bash -s --
#   装完在本机浏览器打开控制台并登录账号 → 设备自动绑定(登录即绑定,无设备码)
set -euo pipefail

CONTROL_PLANE="${CONTROL_PLANE:-https://dsh.yjsm.shop}"
DSH_VERSION="${DSH_VERSION:-0.1.0-rc.6}"
FRP_TOKEN="${FRP_TOKEN:-}"
APP_DIR="${APP_DIR:-$HOME/DeepSeek Harness}"      # dsh 安装目录（本机默认与现有实例一致）
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"                # dsh 数据目录
PLUGIN_SOURCE="${PLUGIN_SOURCE:-auto}"            # auto|url|bundle：翊橘面板分发通道(auto=先服务器 zip 后捆绑兜底)
PLUGIN_URL="${PLUGIN_URL:-https://dsh.yjsm.shop/plugins/dsh-yijv-console.zip}"
PLUGIN_SHA256="${PLUGIN_SHA256:-f5c953a009084aece346cb933f582ff65d33906db21c10ff0938e776b81317d5}"
SKIP_DAEMON=0
for arg in "$@"; do
  case "$arg" in
    --control-plane=*) CONTROL_PLANE="${arg#*=}" ;;
    --dsh-version=*)   DSH_VERSION="${arg#*=}" ;;
    --frp-token=*)     FRP_TOKEN="${arg#*=}" ;;
    --app-dir=*)       APP_DIR="${arg#*=}" ;;
    --dsh-home=*)      DSH_HOME="${arg#*=}" ;;
    --plugin-source=*) PLUGIN_SOURCE="${arg#*=}" ;;
    --plugin-url=*)    PLUGIN_URL="${arg#*=}" ;;
    --plugin-sha256=*) PLUGIN_SHA256="${arg#*=}" ;;
    --skip-daemon)     SKIP_DAEMON=1 ;;
    *) echo "未知参数: $arg" >&2; exit 2 ;;
  esac
done

TRUSTED_HOST="$(printf '%s' "$CONTROL_PLANE" | sed -E 's#^https?://##; s#/.*$##')"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
IS_MAC=0
[[ "$(uname -s)" == "Darwin" ]] && IS_MAC=1
log() { printf '[install] %s\n' "$*"; }

log "控制面: $CONTROL_PLANE | dsh 锁版: $DSH_VERSION | 安装目录: $APP_DIR | DSH_HOME: $DSH_HOME"

# ---------- 1. Node 24+ ----------
if ! command -v node >/dev/null 2>&1; then
  log "未找到 Node，开始安装 Node 24..."
  if [[ $IS_MAC -eq 1 ]]; then
    brew install node@24 || brew install node
  else
    curl -fsSL https://deb.nodesource.com/setup_24.x | sudo bash -
    sudo apt-get install -y nodejs
  fi
fi
NODE_MAJOR="$(node -e 'process.stdout.write(String(process.versions.node.split(".")[0]))')"
if (( NODE_MAJOR < 22 )); then
  log "Node 版本过低（${NODE_MAJOR}），需要 ^22.19 || >=24" >&2; exit 1
fi
log "Node 就绪: $(node --version)"

# ---------- 2. @deepseek-ai/dsh 锁版 ----------
mkdir -p "$APP_DIR"
if [[ ! -f "$APP_DIR/package.json" ]]; then
  printf '{"name":"deepseek-harness","private":true,"type":"commonjs","dependencies":{"@deepseek-ai/dsh":"%s"}}\n' "$DSH_VERSION" > "$APP_DIR/package.json"
fi
if [[ ! -d "$APP_DIR/node_modules/@deepseek-ai/dsh" ]]; then
  log "安装 @deepseek-ai/dsh@${DSH_VERSION}（npm 生成 package-lock.json 锁版）..."
  (cd "$APP_DIR" && npm install --no-audit --no-fund)
else
  INSTALLED="$(node -e "process.stdout.write(require('$APP_DIR/node_modules/@deepseek-ai/dsh/package.json').version)")"
  log "dsh 已安装: ${INSTALLED}（期望 ${DSH_VERSION}）"
fi

# ---------- 3. frpc ----------
if ! command -v frpc >/dev/null 2>&1; then
  log "安装 frpc..."
  if [[ $IS_MAC -eq 1 ]]; then
    brew install frpc
  else
    # Linux x64 官方 release（以实际发布版本为准，可自行替换 URL）
    curl -fsSL -o /tmp/frp.tar.gz https://github.com/fatedier/frp/releases/download/v0.61.0/frp_0.61.0_linux_amd64.tar.gz
    tar -xzf /tmp/frp.tar.gz -C /tmp
    sudo install -m 0755 /tmp/frp_*/frpc /usr/local/bin/frpc
  fi
fi
log "frpc 就绪: $(frpc --version)"

# ---------- 4. $DSH_HOME 初始化 ----------
mkdir -p "$DSH_HOME/profiles/web/plugins" "$DSH_HOME/agent" "$DSH_HOME/knowledge-base"
log "DSH_HOME 初始化完成: $DSH_HOME"

# ---------- 5. 复制设备端代码 ----------
AGENT_DIR="$APP_DIR/dsh-agent"
mkdir -p "$AGENT_DIR/lib" "$AGENT_DIR/plugins" "$AGENT_DIR/daemon"
cp -R "$SCRIPT_DIR/lib/." "$AGENT_DIR/lib/"
cp -R "$SCRIPT_DIR/plugins/." "$AGENT_DIR/plugins/"
cp -R "$SCRIPT_DIR/daemon/." "$AGENT_DIR/daemon/"
log "设备端代码已复制到 $AGENT_DIR"

# ---------- 6. 启动脚本（含 --trusted-host） ----------
cat > "$APP_DIR/start-dsh.sh" <<EOF
#!/bin/zsh
# start-dsh.sh — 启动 dsh web（含 --trusted-host），供 launchd/systemd 调用
export PATH="\$PATH:/opt/homebrew/bin:/usr/local/bin"
cd "$APP_DIR" || exit 1
exec npx dsh web --trusted-host "$TRUSTED_HOST"
EOF
chmod +x "$APP_DIR/start-dsh.sh"
log "启动脚本已写入（--trusted-host ${TRUSTED_HOST}）"

# ---------- 7. 设备注册（登录即绑定：装完在本机浏览器打开控制台并登录账号即自动绑定） ----------
# 0.2c:设备码功能已下线。绑定统一走「登录即绑定」——agent 常驻后监听本机 3081,
#       用户在本机浏览器登录控制台后在「我的设备」点「绑定此设备」即完成注册,无需任何设备码。
log "设备注册方式: 登录即绑定（装完后在本机浏览器打开控制台并登录账号，设备即自动加入「我的设备」，无需设备码）"

# ---------- 7.6 翊橘控制面板（多通道分发：服务器 zip 优先，捆绑兜底） ----------
# PLUGIN_SOURCE=auto|url|bundle；url 通道带 SHA256 硬校验，防止下载被篡改。
# zip 包解压后必须含 dsh-yijv-console/{package.json,client.js,lib/}，目录名即 cordis 插件名。
WEB_PLUGINS="$DSH_HOME/profiles/web/plugins"
mkdir -p "$WEB_PLUGINS"
PATCH="$DSH_HOME/profiles/web/cordis.patch.yml"

sha256_of() {
  if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | awk '{print $1}'
  elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | awk '{print $1}'
  else echo ""; fi
}

install_console_from_bundle() {
  if [[ -d "$AGENT_DIR/plugins/dsh-yijv-console" ]]; then
    rm -rf "$WEB_PLUGINS/dsh-yijv-console"
    cp -R "$AGENT_DIR/plugins/dsh-yijv-console" "$WEB_PLUGINS/"
    log "翊橘控制面板（捆绑分发）已就位"
    return 0
  fi
  return 1
}

install_console_from_url() {
  local tmp zip actual
  command -v curl >/dev/null 2>&1 || { log "缺少 curl，跳过 zip 拉取"; return 1; }
  command -v unzip >/dev/null 2>&1 || { log "缺少 unzip，跳过 zip 拉取"; return 1; }
  tmp="$(mktemp -d)"
  zip="$tmp/dsh-yijv-console.zip"
  if ! curl -fsSL --max-time 60 "$PLUGIN_URL" -o "$zip" 2>/dev/null; then
    log "zip 下载失败: $PLUGIN_URL"
    rm -rf "$tmp"; return 1
  fi
  actual="$(sha256_of "$zip")"
  if [[ -z "$PLUGIN_SHA256" ]] || [[ "$actual" != "$PLUGIN_SHA256" ]]; then
    log "zip 校验失败（期望 ${PLUGIN_SHA256:0:12}...，实际 ${actual:0:12}...），拒绝安装"
    rm -rf "$tmp"; return 1
  fi
  rm -rf "$WEB_PLUGINS/dsh-yijv-console"
  if ! unzip -q "$zip" -d "$WEB_PLUGINS/" 2>/dev/null; then
    log "zip 解压失败"
    rm -rf "$tmp"; return 1
  fi
  rm -rf "$tmp"
  log "翊橘控制面板（服务器 zip 分发）已安装，SHA256 校验通过"
  return 0
}

case "$PLUGIN_SOURCE" in
  url)     install_console_from_url || install_console_from_bundle || true ;;
  bundle)  install_console_from_bundle || true ;;
  *)       install_console_from_url || install_console_from_bundle || true ;;   # auto
esac

# 登记 cordis.patch.yml（幂等：先清后复，重跑不嵌套不重复追加）
if [[ -d "$WEB_PLUGINS/dsh-yijv-console" ]]; then
  if [[ -f "$PATCH" ]] && ! grep -q 'yijv-console' "$PATCH" 2>/dev/null; then
    cat >> "$PATCH" <<'PATCH'

# 翊橘控制面板（install.sh 自动登记）
- insert:
    - id: yijv-console
      name: dsh-yijv-console
PATCH
    log "翊橘控制面板已登记 patch（${PATCH}）"
  elif [[ ! -f "$PATCH" ]]; then
    cat > "$PATCH" <<'PATCH'
# dsh web profile 插件登记（install.sh 生成）
- insert:
    - id: yijv-console
      name: dsh-yijv-console
PATCH
    log "翊橘控制面板已登记 patch（新建 ${PATCH}）"
  else
    log "翊橘控制面板 patch 已存在，跳过登记"
  fi
else
  log "警告: 翊橘控制面板安装失败（url 与捆绑通道均不可用）"
fi

# ---------- 7.7 站点连接配置（siteUrl） ----------
# siteToken 由 site-connector 首次同步时用 device.json 自动换取并回写，此处只写 siteUrl。
if command -v node >/dev/null 2>&1; then
  node -e '
    const fs = require("node:fs"); const path = require("node:path")
    const file = process.argv[1]; const url = process.argv[2]
    const dir = path.dirname(file); fs.mkdirSync(dir, { recursive: true })
    let cur = {}
    try { cur = JSON.parse(fs.readFileSync(file, "utf8")) } catch {}
    cur.siteUrl = url.replace(/\/$/, "")
    fs.writeFileSync(file, JSON.stringify(cur, null, 2) + "\n")
  ' "$DSH_HOME/agent/site.json" "$CONTROL_PLANE"
  log "站点连接配置已写入（$DSH_HOME/agent/site.json）"
fi

# ---------- 7.5 生成 frpc 隧道配置（基于注册返回的 subdomain） ----------
FRP_DIR="$DSH_HOME/frp"
FRP_CONFIG="$FRP_DIR/frpc.toml"
if [[ -f "$DSH_HOME/agent/device.json" ]]; then
  if [[ -z "$FRP_TOKEN" ]]; then
    log "未提供 --frp-token，跳过隧道配置生成（隧道需要 frp 全局 token）"
  elif command -v node >/dev/null 2>&1; then
    log "生成 frpc 隧道配置（${FRP_CONFIG}）..."
    if (cd "$AGENT_DIR" && node -e '
        const { readFileSync } = require("node:fs")
        import("./lib/frpc-conf.mjs").then((m) => {
          const ctx = JSON.parse(readFileSync(process.argv[1], "utf8"))
          const subdomain = ctx.subdomain ?? ctx.device?.subdomain
          if (!subdomain) throw new Error("device.json 缺少 subdomain")
          const toml = m.buildFrpcToml({ subdomain, token: process.argv[3], localPort: 3080 })
          const target = m.writeFrpcConfig({ frpDir: process.argv[2], content: toml })
          console.log(target)
        }).catch((e) => { console.error(e.message); process.exit(1) })
      ' "$DSH_HOME/agent/device.json" "$FRP_DIR" "$FRP_TOKEN" >/tmp/dsh-frp-write.log 2>&1); then
      log "frpc 配置已生成: $(cat /tmp/dsh-frp-write.log)"
    else
      log "frpc 配置生成失败（agent 常驻后会自动补生成）: $(cat /tmp/dsh-frp-write.log)"
    fi
  fi
fi

# ---------- 8. 常驻守护（dsh agent + frpc） ----------
if [[ $SKIP_DAEMON -eq 0 ]]; then
  if [[ $IS_MAC -eq 1 ]]; then
    PLIST="$HOME/Library/LaunchAgents/com.dsh.agent.plist"
    sed -e "s|__AGENT_DIR__|$AGENT_DIR|g" -e "s|__APP_DIR__|$APP_DIR|g" "$AGENT_DIR/daemon/com.dsh.agent.plist" > "$PLIST"
    launchctl unload "$PLIST" 2>/dev/null || true
    launchctl load "$PLIST"
    log "launchd 已注册: $PLIST"

    if [[ -f "$FRP_CONFIG" ]]; then
      FRPC_PLIST="$HOME/Library/LaunchAgents/com.dsh.frpc.plist"
      FRPC_BIN="$(command -v frpc)"
      sed -e "s|__FRPC_BIN__|$FRPC_BIN|g" -e "s|__FRPC_CONFIG__|$FRP_CONFIG|g" -e "s|__FRPC_LOG_DIR__|$FRP_DIR|g" \
        "$AGENT_DIR/daemon/com.dsh.frpc.plist" > "$FRPC_PLIST"
      launchctl unload "$FRPC_PLIST" 2>/dev/null || true
      launchctl load "$FRPC_PLIST"
      log "frpc launchd 已注册: $FRPC_PLIST"
    else
      log "frpc 配置不存在，跳过隧道守护（agent 常驻后会自动补生成）"
    fi
  else
    UNIT="/etc/systemd/system/dsh-agent.service"
    sed -e "s|__AGENT_DIR__|$AGENT_DIR|g" -e "s|__APP_DIR__|$APP_DIR|g" "$AGENT_DIR/daemon/dsh-agent.service" > /tmp/dsh-agent.service
    sudo install -m 0644 /tmp/dsh-agent.service "$UNIT"
    sudo systemctl daemon-reload && sudo systemctl enable --now dsh-agent
    log "systemd 已注册: $UNIT"

    if [[ -f "$FRP_CONFIG" ]]; then
      FRPC_UNIT="/etc/systemd/system/dsh-frpc.service"
      sed -e "s|__FRPC_CONFIG__|$FRP_CONFIG|g" "$AGENT_DIR/daemon/dsh-frpc.service" > /tmp/dsh-frpc.service
      sudo install -m 0644 /tmp/dsh-frpc.service "$FRPC_UNIT"
      sudo systemctl daemon-reload && sudo systemctl enable --now dsh-frpc
      log "frpc systemd 已注册: $FRPC_UNIT"
    fi
  fi
else
  log "跳过守护注册（--skip-daemon）"
fi

log "安装完成。控制面: $CONTROL_PLANE"
