#!/bin/bash
# OpenClaw LingClaw Browser 一键安装脚本 
# 特性: Root 执行 / 目标用户 Ubuntu / VNC防弹窗 / FIFO内存防爆 / 完美DBus穿透

set -e

echo "🚀 LingClaw Browser 安装脚本 (Root 全自动部署版)"
echo "==========================================================="

# 1. 强制要求使用 root 运行
if [ "$EUID" -ne 0 ]; then 
   echo "⚠️  请使用 root 用户运行此脚本！(例如: sudo bash install.sh 或切换到 root 用户)"
   exit 1
fi

# ================= 2. 核心配置变量 =================
TARGET_USER="ubuntu"  # 目标运行用户

INSTALL_DIR="/opt/lingclaw-browser"
DATA_DIR="$INSTALL_DIR/data"
AUTH_DIR="/opt/lingclaw-browser-auth"
EXT_DIR="$INSTALL_DIR/extension-env-control" 

# 端口与网络配置
CDP_PORT="18900"
NOVNC_PORT="19900"
VNC_SOCK="/tmp/lingclaw-browser-vnc.sock"
EXPECTED_TOKEN="sk-91a3cc5a1c6f4c45aa294764c4f88150" # <--- 修改你的静态鉴权 Token

# 显示与浏览器控制设置
RESOLUTION="1366x768"
RESOLUTION_CHROME="1366,768"
COLOR_DEPTH="24"
MAX_TABS="5" 

# 服务名称
SVC_XVNC="lingclaw-xvnc"
SVC_WEBSOCKIFY="lingclaw-websockify"
SVC_CHROME="lingclaw-chrome" 
# =================================================

# 确保目标用户存在
if ! id "$TARGET_USER" &>/dev/null; then
    echo "创建目标用户 $TARGET_USER ..."
    useradd -m -s /bin/bash "$TARGET_USER"
fi

# 3. 安装基础依赖 (移除 sudo)
echo "📦 步骤 1/9: 安装系统与 VNC 依赖..."
apt-get update -qq
apt-get install -y -qq fonts-noto-cjk fonts-noto-cjk-extra xdg-utils curl jq \
                       tigervnc-standalone-server novnc websockify \
                       software-properties-common wget 2>/dev/null || true

# 4. 彻底清理 Snap 并强制安装原生 Chromium
echo "🔍 步骤 2/9: 清理旧版并安装原生 Chromium..."
if command -v snap &> /dev/null; then
    snap remove chromium || true
fi
apt-get purge -y chromium-browser || true

add-apt-repository -y ppa:xtradeb/apps > /dev/null 2>&1
apt-get update -qq
apt-get install -y -qq chromium || {
    echo "❌ 原生 Chromium 安装失败"
    exit 1
}

# 5. 创建目录与配置鉴权插件
echo "📁 步骤 3/9: 创建目录及 Websockify 鉴权配置..."
mkdir -p "$DATA_DIR" "$AUTH_DIR" "$EXT_DIR"

cat << EOF > "$AUTH_DIR/header_auth.py"
import logging

class StaticTokenAuth:
    def __init__(self, config=None):
        self.expected_token = "$EXPECTED_TOKEN"

    def authenticate(self, headers, target_host, target_port):
        token = headers.get('X-Vnc-Token') or headers.get('x-vnc-token')
        if token == self.expected_token:
            return True
        raise Exception("Unauthorized")
EOF

# 6. 生成环境控制扩展
echo "🧩 步骤 4/9: 生成环境控制扩展 (强制标签页 + FIFO 淘汰)..."

cat << EOF > "$EXT_DIR/manifest.json"
{
  "manifest_version": 3,
  "name": "LingClaw Env Control",
  "version": "2.0",
  "description": "强制所有新窗口为新标签页，并采用 FIFO 策略淘汰旧标签页以控制内存。",
  "permissions": ["tabs"],
  "background": {
    "service_worker": "background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["inject.js"],
      "run_at": "document_start",
      "world": "MAIN"
    }
  ]
}
EOF

cat << EOF > "$EXT_DIR/inject.js"
const originalOpen = window.open;
window.open = function(url, name, features) {
    return originalOpen.call(window, url, name, ""); 
};
EOF

cat << EOF > "$EXT_DIR/background.js"
const MAX_TABS = $MAX_TABS;

chrome.tabs.onCreated.addListener((newTab) => {
    chrome.tabs.query({ windowId: newTab.windowId }, (tabs) => {
        if (tabs.length > MAX_TABS) {
            let oldestTab = tabs.reduce((prev, curr) => (prev.id < curr.id ? prev : curr));
            chrome.tabs.remove(oldestTab.id);
            console.log("LingClaw: 超过最大限制 (" + MAX_TABS + ")，已关闭最早的标签页 (ID: " + oldestTab.id + ")。");
        }
    });
});
EOF

# 7. 设置全量目录权限给目标用户
echo "🔑 步骤 5/9: 配置目录权限给 $TARGET_USER ..."
chown -R "$TARGET_USER:$TARGET_USER" "$INSTALL_DIR" "$AUTH_DIR"
chmod 750 "$AUTH_DIR"
chmod 640 "$AUTH_DIR/header_auth.py"

# 8. 创建全部 Systemd 服务文件 (User=$TARGET_USER)
echo "📝 步骤 6/9: 创建 Systemd 守护进程服务..."

cat << EOF > /etc/systemd/system/${SVC_XVNC}.service
[Unit]
Description=LingClaw Xvnc Server
After=network.target

[Service]
User=$TARGET_USER
Type=simple
ExecStartPre=/bin/rm -f $VNC_SOCK /tmp/.X99-lock
ExecStart=/usr/bin/Xvnc :99 -geometry $RESOLUTION -depth $COLOR_DEPTH -rfbunixpath $VNC_SOCK -nolisten tcp -SecurityTypes None
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

cat << EOF > /etc/systemd/system/${SVC_WEBSOCKIFY}.service
[Unit]
Description=LingClaw Websockify Bridge
Requires=${SVC_XVNC}.service
After=${SVC_XVNC}.service

[Service]
User=$TARGET_USER
Type=simple
Environment="PYTHONPATH=$AUTH_DIR"
ExecStart=/usr/bin/websockify --web /usr/share/novnc/ --auth-plugin header_auth.StaticTokenAuth 0.0.0.0:$NOVNC_PORT --unix-target=$VNC_SOCK
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF

cat << EOF > /etc/systemd/system/${SVC_CHROME}.service
[Unit]
Description=Headless Chrome with CDP and VNC
Requires=${SVC_XVNC}.service
After=${SVC_XVNC}.service

[Service]
Type=simple
User=$TARGET_USER
Group=$TARGET_USER

Environment="CHROME_DATA_DIR=$DATA_DIR"
Environment="CHROME_CDP_PORT=$CDP_PORT"
Environment="DISPLAY=:99"

WorkingDirectory=$INSTALL_DIR

ExecStart=/usr/bin/chromium \\
    --disable-gpu \\
    --window-size=$RESOLUTION_CHROME \\
    --window-position=0,0 \\
    --lang=zh-CN \\
    --accept-lang=zh-CN,en-US,en \\
    --user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" \\
    --no-sandbox \\
    --disable-dev-shm-usage \\
    --disable-setuid-sandbox \\
    --remote-debugging-address=127.0.0.1 \\
    --remote-debugging-port=$CDP_PORT \\
    --user-data-dir=$DATA_DIR \\
    --load-extension=$EXT_DIR \\
    --disable-background-networking \\
    --disable-background-timer-throttling \\
    --disable-client-side-phishing-detection \\
    --disable-default-apps \\
    --disable-hang-monitor \\
    --disable-popup-blocking \\
    --disable-prompt-on-repost \\
    --disable-sync \\
    --metrics-recording-only \\
    --no-first-run \\
    --safebrowsing-disable-auto-update \\
    --disable-blink-features=AutomationControlled \\
    --password-store=basic \\
    --use-mock-keychain \\
    about:blank

Restart=always
RestartSec=5
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

# 9. 重新加载并智能启动/重启服务
echo "🚀 步骤 7/9: 检测并启动/重启服务..."
systemctl daemon-reload

SERVICES=($SVC_XVNC $SVC_WEBSOCKIFY $SVC_CHROME)

for svc in "${SERVICES[@]}"; do
    systemctl enable $svc > /dev/null 2>&1
    if systemctl is-active --quiet $svc; then
        echo "   🔄 检测到 $svc 正在运行，正在重启以应用新配置..."
    else
        echo "   ▶️ 正在启动全新服务 $svc..."
    fi
    systemctl restart $svc > /dev/null 2>&1
done

# 10. 等待服务启动并验证
echo "⏳ 步骤 8/9: 等待 CDP 服务就绪..."
sleep 3
for i in {1..10}; do
    if curl -s "http://localhost:$CDP_PORT/json/version" > /dev/null 2>&1; then
        echo "✅ Chrome CDP 服务已启动 (仅限本地 127.0.0.1 访问)"
        break
    fi
    sleep 1
done

# 11. 配置 OpenClaw (利用临时脚本和 su 实现完美环境穿透)
echo "⚙️  步骤 9/9: 配置 OpenClaw (以 $TARGET_USER 身份执行)..."

OC_TMP_SCRIPT="/tmp/openclaw_setup_$$.sh"

cat << EOF > "$OC_TMP_SCRIPT"
#!/bin/bash
# 加载 Brew 环境 (忽略报错以防未安装)
eval "\$(/home/linuxbrew/.linuxbrew/bin/brew shellenv 2>/dev/null || true)"

# 注入用户 DBus 总线环境 (确保 gateway restart 能够通信)
export XDG_RUNTIME_DIR="/run/user/\$(id -u)"
export DBUS_SESSION_BUS_ADDRESS="unix:path=\${XDG_RUNTIME_DIR}/bus"

if command -v openclaw &> /dev/null; then
    openclaw config set browser.profiles.lingclaw '{"color":"#00AA00","cdpUrl":"http://localhost:$CDP_PORT"}' --strict-json 2>/dev/null || true
    openclaw config set browser.defaultProfile lingclaw 2>/dev/null || true
    openclaw config set browser.attachOnly true 2>/dev/null || true
    echo "✅ OpenClaw 配置参数写入完成"
    
    echo "🔄 尝试重启 OpenClaw Gateway..."
    if openclaw gateway restart; then
        echo "✅ OpenClaw Gateway 重启成功！"
    else
        echo "⚠️ Gateway 重启指令下发失败。如果服务异常，请后续手动切换到 $TARGET_USER 执行: openclaw gateway restart"
    fi
else
    echo "⚠️  未在 $TARGET_USER 环境变量下找到 openclaw 命令，跳过自动配置。"
fi
EOF

# 赋予执行权限并强制切换到目标用户运行该临时脚本
chmod +x "$OC_TMP_SCRIPT"
chown "$TARGET_USER:$TARGET_USER" "$OC_TMP_SCRIPT"

su - "$TARGET_USER" -c "$OC_TMP_SCRIPT"

# 清理临时脚本
rm -f "$OC_TMP_SCRIPT"

echo ""
echo "================================================="
echo "🎉 安装与更新全部完成!"
echo "   🛡️ 安全机制: CDP已绑定至127.0.0.1"
echo "   ✅ 服务机制: 由 Root 部署，系统级后台以 $TARGET_USER 运行"
echo "   ✅ 环境穿透: OpenClaw 守护进程配置已安全写入并尝试重启"
echo "   📺 VNC 鉴权 Token: $EXPECTED_TOKEN"
echo "================================================="