#!/usr/bin/env bash
set -u

export PATH="/opt/homebrew/opt/node@24/bin:$HOME/.npm-global/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"

OC="$HOME/.npm-global/bin/openclaw"
CFG="$HOME/.openclaw/openclaw.json"
MODEL_FULL="nvidia-nim/deepseek-ai/deepseek-v4-flash"
MODEL_ID="deepseek-ai/deepseek-v4-flash"
PORT=18789
LOCKDIR="/tmp/openclaw-restore-nvidia.lock"
RUNLOG="$HOME/Desktop/還原到NVIDIA.log"

mkdir -p "$HOME/.openclaw" "$HOME/Library/Logs/openclaw" "$(dirname "$RUNLOG")"
touch "$RUNLOG"
exec > >(tee -a "$RUNLOG") 2>&1

echo ""
echo "=== 還原到 NVIDIA：完整防當機整合版 ==="
echo ""

if [ ! -x "$OC" ]; then
  OC="$(command -v openclaw || true)"
fi

if [ -z "${OC:-}" ]; then
  echo "❌ 找不到 openclaw"
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 1
fi

interrupt_previous_tasks() {
  echo ""
  echo "0. 先中斷前一次卡住的任務"

  for pid in $(pgrep -f "還原到NVIDIA.command" 2>/dev/null || true); do
    [ "$pid" = "$$" ] && continue
    [ "$pid" = "$PPID" ] && continue
    echo "停止舊還原程式 PID: $pid"
    kill -TERM "$pid" 2>/dev/null || true
  done

  pkill -TERM -f "openclaw.*doctor|openclaw.*skills|openclaw.*gateway|openclaw.*logs|openclaw.*config|node.*openclaw|ai.openclaw.gateway" 2>/dev/null || true
  sleep 5

  for pid in $(pgrep -f "還原到NVIDIA.command" 2>/dev/null || true); do
    [ "$pid" = "$$" ] && continue
    [ "$pid" = "$PPID" ] && continue
    kill -KILL "$pid" 2>/dev/null || true
  done

  pkill -KILL -f "openclaw.*doctor|openclaw.*skills|openclaw.*gateway|openclaw.*logs|openclaw.*config|node.*openclaw|ai.openclaw.gateway" 2>/dev/null || true

  for pid in $(lsof -tiTCP:$PORT -sTCP:LISTEN 2>/dev/null || true); do
    echo "釋放 port $PORT PID: $pid"
    kill -TERM "$pid" 2>/dev/null || true
  done

  sleep 3

  for pid in $(lsof -tiTCP:$PORT -sTCP:LISTEN 2>/dev/null || true); do
    kill -KILL "$pid" 2>/dev/null || true
  done

  rm -rf "$LOCKDIR" 2>/dev/null || true
}

interrupt_previous_tasks

cleanup_lock() {
  rm -rf "$LOCKDIR" 2>/dev/null || true
}
trap cleanup_lock EXIT INT TERM

if ! mkdir "$LOCKDIR" 2>/dev/null; then
  echo "⚠️ 還原程式已經在跑。已避免重複啟動。"
  echo "如果你確定沒有在跑，請貼：rm -rf $LOCKDIR"
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 0
fi

safe_run() {
  local sec="$1"
  shift

  echo ""
  echo "▶ 執行：$*"
  echo "  timeout: ${sec}s"

  "$@" &
  local pid=$!
  local elapsed=0

  while kill -0 "$pid" 2>/dev/null; do
    if [ "$elapsed" -ge "$sec" ]; then
      echo "⚠️ 超時，停止：$*"
      pkill -TERM -P "$pid" 2>/dev/null || true
      kill -TERM "$pid" 2>/dev/null || true
      sleep 3
      pkill -KILL -P "$pid" 2>/dev/null || true
      kill -KILL "$pid" 2>/dev/null || true
      wait "$pid" 2>/dev/null || true
      return 124
    fi
    sleep 1
    elapsed=$((elapsed + 1))
  done

  wait "$pid"
  return $?
}

stop_gateway_hard() {
  echo ""
  echo "▶ 完全停止 Gateway"
  safe_run 25 "$OC" gateway stop || true
  launchctl bootout "gui/$(id -u)" "$HOME/Library/LaunchAgents/ai.openclaw.gateway.plist" 2>/dev/null || true
  pkill -TERM -f "openclaw.*doctor|openclaw.*skills|openclaw.*gateway|openclaw.*logs|openclaw.*config|node.*openclaw|ai.openclaw.gateway" 2>/dev/null || true
  sleep 5
  pkill -KILL -f "openclaw.*doctor|openclaw.*skills|openclaw.*gateway|openclaw.*logs|openclaw.*config|node.*openclaw|ai.openclaw.gateway" 2>/dev/null || true
  sleep 3
}

fix_node_paths() {
  perl -0pi -e 's#/usr/local/bin/node#/opt/homebrew/opt/node@24/bin/node#g; s#/opt/homebrew/opt/node@22/bin/node#/opt/homebrew/opt/node@24/bin/node#g; s#/opt/homebrew/opt/node@23/bin/node#/opt/homebrew/opt/node@24/bin/node#g' \
    "$HOME/Library/LaunchAgents/ai.openclaw.gateway.plist" \
    "$HOME/.openclaw/service-env/ai.openclaw.gateway-env-wrapper.sh" \
    "$HOME/.openclaw/service-env/ai.openclaw.gateway.env" 2>/dev/null || true
}

write_nvidia_config() {
  node <<'NODE'
const fs = require("fs");

const home = process.env.HOME;
const p = home + "/.openclaw/openclaw.json";
const c = JSON.parse(fs.readFileSync(p, "utf8"));

const MODEL_FULL = "nvidia-nim/deepseek-ai/deepseek-v4-flash";
const MODEL_ID = "deepseek-ai/deepseek-v4-flash";

function obj(x) {
  return x && typeof x === "object" && !Array.isArray(x);
}

c.gateway = obj(c.gateway) ? c.gateway : {};
c.gateway.mode = "local";
c.gateway.bind = "loopback";
c.gateway.port = 18789;

c.models = obj(c.models) ? c.models : {};
c.models.providers = obj(c.models.providers) ? c.models.providers : {};

const oldNim = c.models.providers["nvidia-nim"];
const oldCustom = c.models.providers["nvidia-custom"];

const key =
  oldNim?.apiKey ||
  oldCustom?.apiKey ||
  process.env.NVIDIA_API_KEY ||
  "";

if (!key) {
  console.error("MISSING_NVIDIA_KEY");
  process.exit(42);
}

c.models.providers["nvidia-nim"] = {
  baseUrl: "https://integrate.api.nvidia.com/v1",
  apiKey: key,
  api: "openai-completions",
  models: [
    {
      id: MODEL_ID,
      name: "DeepSeek V4 Flash on NVIDIA NIM",
      input: ["text"],
      contextWindow: 1048576,
      maxTokens: 8192,
      reasoning: false,
      cost: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0
      }
    }
  ]
};

if (obj(c.channels?.telegram) && c.channels.telegram.bindings) {
  delete c.channels.telegram.bindings;
}

c.agents = obj(c.agents) ? c.agents : {};
c.agents.defaults = obj(c.agents.defaults) ? c.agents.defaults : {};

function applyAgent(agent) {
  if (!obj(agent)) return;

  agent.model = {
    primary: MODEL_FULL,
    fallbacks: []
  };

  agent.models = {
    [MODEL_FULL]: {}
  };
}

applyAgent(c.agents.defaults);

if (Array.isArray(c.agents.list)) {
  for (const a of c.agents.list) {
    applyAgent(a);
  }
}

for (const [name, agent] of Object.entries(c.agents)) {
  if (name === "defaults" || name === "list") continue;
  applyAgent(agent);
}

let validAgentIds = new Set();

if (Array.isArray(c.agents.list)) {
  for (const a of c.agents.list) {
    if (typeof a === "string") validAgentIds.add(a);
    else if (obj(a) && a.id) validAgentIds.add(a.id);
  }
}

if (c.agents.main) validAgentIds.add("main");
if (validAgentIds.size === 0) validAgentIds.add("main");

const fallbackAgent = validAgentIds.has("main") ? "main" : [...validAgentIds][0];

if (Array.isArray(c.bindings)) {
  for (const b of c.bindings) {
    if (!obj(b)) continue;
    if (!b.agentId || !validAgentIds.has(b.agentId)) {
      b.agentId = fallbackAgent;
    }
  }
}

fs.mkdirSync(home + "/.openclaw/ocboot", { recursive: true });
fs.writeFileSync(home + "/.openclaw/ocboot/last-model", MODEL_FULL);

fs.writeFileSync(p, JSON.stringify(c, null, 2));
console.log("已硬切回：" + MODEL_FULL);
NODE
}

echo "1. OpenClaw：$OC"
"$OC" --version 2>/dev/null || true

echo ""
echo "2. Node 檢查"
which node || true
node -v || true

node -e '
const v = process.versions.node.split(".").map(Number);
if (v[0] < 24 || (v[0] === 24 && v[1] < 15)) process.exit(1);
' || {
  echo "❌ Node 版本不足，現在吃到的是：$(which node) $(node -v)"
  echo "需要 /opt/homebrew/opt/node@24/bin/node 24.15+"
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 1
}

if [ ! -f "$CFG" ]; then
  echo ""
  echo "找不到 config，先跑 doctor --fix"
  safe_run 90 "$OC" doctor --fix || true
fi

if [ ! -f "$CFG" ]; then
  echo "❌ 找不到 $CFG"
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 1
fi

stop_gateway_hard
fix_node_paths

echo ""
echo "3. 備份 config"
TS=$(date +%Y%m%d-%H%M%S)
cp "$CFG" "$CFG.restore-nvidia.$TS.bak"
echo "備份：$CFG.restore-nvidia.$TS.bak"

echo ""
echo "4. 寫入 NVIDIA 設定"
write_nvidia_config
RC=$?

if [ "$RC" -eq 42 ]; then
  echo ""
  read -r -s -p "找不到 NVIDIA API key，請輸入 nvapi key，不會顯示： " NVIDIA_API_KEY
  echo ""
  export NVIDIA_API_KEY

  if [ -z "$NVIDIA_API_KEY" ]; then
    echo "❌ 沒有輸入 NVIDIA API key"
    read -n 1 -s -r -p "按任意鍵關閉..."
    exit 1
  fi

  write_nvidia_config
  RC=$?
fi

if [ "$RC" -ne 0 ]; then
  echo "❌ 寫入 NVIDIA config 失敗"
  cp "$CFG.restore-nvidia.$TS.bak" "$CFG" 2>/dev/null || true
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 1
fi

echo ""
echo "5. 驗證 config"
if ! safe_run 60 "$OC" config validate; then
  echo "❌ config 驗證失敗，已還原備份"
  cp "$CFG.restore-nvidia.$TS.bak" "$CFG" 2>/dev/null || true
  read -n 1 -s -r -p "按任意鍵關閉..."
  exit 1
fi

echo ""
echo "6. 修復技能 / 狀態"
safe_run 90 "$OC" doctor --fix || true
safe_run 90 "$OC" skills repair || true
safe_run 90 "$OC" skills sync || true

echo ""
echo "7. 技能修復後再硬寫一次 NVIDIA"
write_nvidia_config || true
safe_run 60 "$OC" config validate || true

echo ""
echo "8. 重新安裝 Gateway"
stop_gateway_hard
fix_node_paths
safe_run 90 "$OC" gateway install --force || true
fix_node_paths
safe_run 90 "$OC" gateway restart || safe_run 90 "$OC" gateway start || true

echo ""
echo "9. 等待 Gateway 啟動"
sleep 20

echo ""
echo "10. 狀態"
"$OC" gateway status --deep 2>&1 | egrep -i "Runtime|Connectivity|Listening|agent model|CLI version|Gateway version|node" || true
lsof -nP -iTCP:$PORT -sTCP:LISTEN || true

echo ""
if lsof -nP -iTCP:$PORT -sTCP:LISTEN >/dev/null 2>&1; then
  echo "✅ 完成：已還原到 $MODEL_FULL"
  echo "Telegram 請傳：/new，然後 hi"
else
  echo "⚠️ Gateway 還沒 listening，最後錯誤："
  TMPLOG="/tmp/openclaw-restore-nvidia-log.$$"
  safe_run 45 "$OC" logs --max-bytes 900000 > "$TMPLOG" 2>&1 || true
  egrep -i "gateway|nvidia|deepseek|migration|node|missing|api key|401|403|404|429|schema|thinking|failed|error|listening" "$TMPLOG" | tail -120 || true
  rm -f "$TMPLOG" 2>/dev/null || true
fi

echo ""
echo "Log：$RUNLOG"
read -n 1 -s -r -p "按任意鍵關閉..."
