#!/usr/bin/env bash

set -euo pipefail

# ── Colour helpers ────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
info()    { echo -e "${CYAN}[INFO]${NC}  $*"; }
success() { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC}  $*"; }
error()   { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; }

# ── Config ────────────────────────────────────────────────────────────────────
OPENCLAW_USER="openclaw"            # Dedicated non-root user for OpenClaw
NODE_MAJOR=22                       # OpenClaw requires Node 22+
OPENCLAW_PORT=18789                 # Default gateway port
INSTRUCTIONS_FILE="$HOME/openclaw_configuration_guide.txt"

# ── Phase 1: Root bootstrap — create user and re-execute as that user ─────────
if [[ "$EUID" -eq 0 ]]; then
    info "Running as root — bootstrapping '${OPENCLAW_USER}' user..."

    # Ensure sudo is available (may be absent on a truly minimal image)
    if ! command -v sudo >/dev/null 2>&1; then
        info "sudo not found — installing it..."
        apt-get update -qq
        apt-get install -y -qq sudo
        success "sudo installed."
    fi

    # Create the user if it doesn't already exist
    if id "${OPENCLAW_USER}" &>/dev/null; then
        warn "User '${OPENCLAW_USER}' already exists — skipping creation."
    else
        adduser "${OPENCLAW_USER}" --gecos "" --disabled-password
        success "User '${OPENCLAW_USER}' created."
    fi

    # Grant sudo membership
    usermod -aG sudo "${OPENCLAW_USER}"
    success "User '${OPENCLAW_USER}' added to the sudo group."

    # Allow passwordless sudo so the re-executed script never hangs on a prompt
    SUDOERS_FILE="/etc/sudoers.d/openclaw-install"
    if [[ ! -f "$SUDOERS_FILE" ]]; then
        echo "${OPENCLAW_USER} ALL=(ALL) NOPASSWD: ALL" > "$SUDOERS_FILE"
        chmod 0440 "$SUDOERS_FILE"
        success "Passwordless sudo configured for '${OPENCLAW_USER}' (install phase only)."
    fi

    # Copy this script into the new user's home so it can re-run itself there
    SCRIPT_PATH="$(realpath "$0")"
    TARGET_SCRIPT="/home/${OPENCLAW_USER}/$(basename "$SCRIPT_PATH")"
    cp "$SCRIPT_PATH" "$TARGET_SCRIPT"
    chown "${OPENCLAW_USER}:${OPENCLAW_USER}" "$TARGET_SCRIPT"
    chmod +x "$TARGET_SCRIPT"

    info "Switching to '${OPENCLAW_USER}' and continuing installation..."
    echo
    # Re-execute this script as the dedicated user; exec replaces this process
    # so nothing below this line ever runs as root.
    exec su - "${OPENCLAW_USER}" -c "bash '$TARGET_SCRIPT'"
fi

# ── Phase 2: Non-root installation ───────────────────────────────────────────
command -v sudo >/dev/null 2>&1 || error "sudo is required but not found."

info "Starting OpenClaw installation as '$(whoami)'..."
echo

# ── 1. System update & base dependencies ─────────────────────────────────────
info "Updating package index and installing base dependencies..."
sudo apt-get update -qq
sudo apt-get install -y -qq \
    curl \
    wget \
    git \
    ca-certificates \
    gnupg \
    lsb-release \
    ufw \
    2>/dev/null
success "Base dependencies installed."

# ── 2. Install Node.js 22+ via NodeSource ────────────────────────────────────
install_node() {
    info "Installing Node.js ${NODE_MAJOR}..."
    curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | sudo -E bash - >/dev/null 2>&1
    sudo apt-get install -y -qq nodejs
    success "Node.js $(node --version) installed."
}

if command -v node >/dev/null 2>&1; then
    CURRENT_NODE=$(node --version | sed 's/v//' | cut -d. -f1)
    if [[ "$CURRENT_NODE" -lt "$NODE_MAJOR" ]]; then
        warn "Node.js $CURRENT_NODE found — too old (need $NODE_MAJOR+). Upgrading..."
        install_node
    else
        success "Node.js $(node --version) already satisfies the requirement."
    fi
else
    install_node
fi

# ── 3. Point npm global prefix to a user-owned directory ─────────────────────
NPM_GLOBAL_DIR="$HOME/.npm-global"
NPM_BIN_DIR="${NPM_GLOBAL_DIR}/bin"

info "Configuring npm global prefix → ${NPM_GLOBAL_DIR}..."
mkdir -p "$NPM_GLOBAL_DIR"
npm config set prefix "$NPM_GLOBAL_DIR"

# Export for the current shell session
export PATH="${NPM_BIN_DIR}:$PATH"

# Persist for future interactive shells — avoid duplicate entries
for RC_FILE in "$HOME/.bashrc" "$HOME/.profile"; do
    if ! grep -qF "NPM_GLOBAL_DIR" "$RC_FILE" 2>/dev/null; then
        {
            echo ""
            echo "# npm user-global prefix (set by install_openclaw.sh)"
            echo "export PATH=\"${NPM_BIN_DIR}:\$PATH\""
        } >> "$RC_FILE"
    fi
done
success "npm prefix set to ${NPM_GLOBAL_DIR}."

# ── 4. Install OpenClaw CLI via npm ──────────────────────────────────────────
info "Installing OpenClaw CLI globally via npm (this may take a minute)..."
npm install -g openclaw@latest

# Verify the binary is reachable
if ! command -v openclaw >/dev/null 2>&1; then
    error "openclaw binary not found after install.\nPATH=${PATH}\nnpm prefix=$(npm prefix -g)"
fi
success "OpenClaw $(openclaw --version 2>/dev/null || echo 'installed — version available after first run') installed."

# ── 5. Basic firewall: allow only SSH + OpenClaw gateway ─────────────────────
info "Configuring UFW firewall..."
sudo ufw --force reset >/dev/null 2>&1
sudo ufw default deny incoming >/dev/null 2>&1
sudo ufw default allow outgoing >/dev/null 2>&1
sudo ufw allow OpenSSH >/dev/null 2>&1
sudo ufw allow "${OPENCLAW_PORT}/tcp" comment "OpenClaw gateway" >/dev/null 2>&1
sudo ufw --force enable >/dev/null 2>&1
success "Firewall configured (SSH + port ${OPENCLAW_PORT} open)."

# ── 6. Generate the configuration instructions file ──────────────────────────
info "Writing configuration guide to ${INSTRUCTIONS_FILE}..."

cat > "$INSTRUCTIONS_FILE" << 'EOF'
================================================================================
  OPENCLAW — POST-INSTALL CONFIGURATION GUIDE
  Generated automatically by install_openclaw.sh
================================================================================

OpenClaw is now installed on this machine.
The next steps below are interactive and must be completed manually.

────────────────────────────────────────────────────────────────────────────────
STEP 1 — RUN THE ONBOARDING WIZARD
────────────────────────────────────────────────────────────────────────────────
OpenClaw was installed under the openclaw user. Switch to that user first:
    su - openclaw

Run the following command in your terminal to launch the interactive setup:

    openclaw onboard --install-daemon

The wizard will guide you through:
  • Accepting the risk acknowledgement
  • Choosing QuickStart (recommended) or Advanced setup
  • Selecting your AI provider & entering your API key (see STEP 2)
  • Configuring the gateway port (default: 18789)
  • Setting the bind address (see SECURITY NOTE below)
  • Optionally connecting messaging channels (Telegram, WhatsApp, Discord…)
  • Installing the background daemon (systemd on Linux)

After onboarding completes, verify the gateway is running:

    openclaw status
    openclaw doctor      # automated health check

────────────────────────────────────────────────────────────────────────────────
STEP 2 — API KEY(S)
────────────────────────────────────────────────────────────────────────────────
You need at least one LLM provider API key. Obtain it BEFORE running the wizard.

  • Anthropic (Claude)   → https://console.anthropic.com/keys
  • OpenAI (GPT)         → https://platform.openai.com/api-keys
  • Google (Gemini)      → https://aistudio.google.com/app/apikey
  • Local model (Ollama) → No API key needed; install Ollama separately first.
                           https://ollama.com/download

The wizard will prompt you to paste the key — it is stored encrypted in
~/.openclaw/config.json.  Do not share or commit that file.

────────────────────────────────────────────────────────────────────────────────
STEP 3 — CONNECT A MESSAGING CHANNEL (optional but recommended)
────────────────────────────────────────────────────────────────────────────────
OpenClaw works with: Telegram, WhatsApp, Discord, Slack, Signal, iMessage,
Microsoft Teams, Matrix, Google Chat, and a built-in WebChat.

You can set channels up during onboarding or afterwards:

    openclaw onboard        # re-run wizard at any time (safe)

TELEGRAM (most common setup):
  1. Open Telegram → search for @BotFather
  2. Send /newbot → follow the prompts → copy the API token
  3. During onboarding, choose Telegram and paste the token
  4. Send /start to your new bot, then approve the pairing code shown in the CLI

DISCORD:
  1. Go to https://discord.com/developers/applications
  2. Create a new application → Bot section → copy the token
  3. Enable "Message Content Intent" under Privileged Gateway Intents
  4. Invite the bot to your server using the OAuth2 URL generator
  5. Provide the token during onboarding and allowlist your user ID in the config

WHATSAPP:
  Follow the prompts during onboarding — OpenClaw will display a QR code.
  Scan it with the WhatsApp mobile app (Linked Devices → Link a Device).

────────────────────────────────────────────────────────────────────────────────
STEP 4 — ACCESS THE WEB DASHBOARD
────────────────────────────────────────────────────────────────────────────────
After the daemon is running, open the dashboard in your browser:

    openclaw dashboard      # copies the URL and tries to open your browser

Default URL (if accessing remotely via SSH tunnel):

    http://localhost:18789/

To create a secure SSH tunnel from your local machine:

    ssh -L 18789:localhost:18789 <user>@<VM_IP>

Then open http://localhost:18789 in your local browser.

────────────────────────────────────────────────────────────────────────────────
STEP 5 — INSTALL SKILLS
────────────────────────────────────────────────────────────────────────────────
Skills extend OpenClaw's capabilities (web browsing, calendar, file management…).
OpenClaw ships with 50+ skills in the registry.

Browse & install from the dashboard:  Skills → Search → Install

Or from the CLI:

    openclaw skills list
    openclaw skills install <skill-name>

Vet community skills before installing — some may contain malware.
    Use the Cisco Skill Scanner if available.

────────────────────────────────────────────────────────────────────────────────
STEP 6 — DAEMON MANAGEMENT
────────────────────────────────────────────────────────────────────────────────
The --install-daemon flag registers OpenClaw with systemd so it restarts on boot.

Useful commands:

    openclaw status                  # check gateway health
    openclaw gateway restart         # restart the gateway
    openclaw logs --follow           # live log stream
    openclaw doctor                  # diagnose configuration issues
    openclaw update --channel stable # update to latest stable release

────────────────────────────────────────────────────────────────────────────────
SECURITY NOTES
────────────────────────────────────────────────────────────────────────────────
OpenClaw has shell-level access to your system. Follow these hardening steps:

1. BIND TO LOCALHOST only — do NOT expose the gateway to the public internet.
   In ~/.openclaw/openclaw.json (created after onboarding), set:
       "gateway": { "bind": "127.0.0.1" }

2. ENABLE EXEC APPROVAL — require consent before write/exec commands:
   In openclaw.json, set:
       "exec": { "ask": "on" }

3. NEVER run OpenClaw as root.

4. Treat ~/.openclaw like a password vault — it contains your API keys and tokens.

5. Do not install unvetted community skills.

6. Use a dedicated non-personal VM or VPS for OpenClaw.

────────────────────────────────────────────────────────────────────────────────
TROUBLESHOOTING
────────────────────────────────────────────────────────────────────────────────
  • "openclaw: command not found"
    → Run: export PATH="$(npm prefix -g)/bin:$PATH"
    → Then add that line permanently to ~/.bashrc

  • "RPC probe: failed" / port error
    → Port 18789 may be in use: sudo lsof -i :18789
    → Or change the port during onboarding / in openclaw.json

  • "Gateway not responding" / 0 tokens used
    → Run: openclaw gateway restart
    → Check API key validity in openclaw.json

  • "EACCES" errors (npm permissions)
    → Do NOT use sudo with npm. Fix npm prefix ownership:
        mkdir -p ~/.npm-global
        npm config set prefix '~/.npm-global'
        export PATH="$HOME/.npm-global/bin:$PATH"

  • "sharp" build error during install
    → Re-install with: SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install -g openclaw@latest

────────────────────────────────────────────────────────────────────────────────
USEFUL LINKS
────────────────────────────────────────────────────────────────────────────────
  Official docs       → https://docs.openclaw.ai
  GitHub repository   → https://github.com/openclaw/openclaw
  Install page        → https://docs.openclaw.ai/install
  Channel setup docs  → https://docs.openclaw.ai/channels
  Skills registry     → https://docs.openclaw.ai/skills
  Community / issues  → https://github.com/openclaw/openclaw/discussions

================================================================================
EOF

success "Configuration guide written to: ${INSTRUCTIONS_FILE}"

# ── 7. Summary ────────────────────────────────────────────────────────────────
echo
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║           OPENCLAW INSTALLATION COMPLETE                    ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
echo
echo -e "  Node.js version : ${CYAN}$(node --version)${NC}"
echo -e "  npm version     : ${CYAN}$(npm --version)${NC}"
echo -e "  OpenClaw CLI    : ${CYAN}$(which openclaw)${NC}"
echo -e "  Gateway port    : ${CYAN}${OPENCLAW_PORT}${NC}"
echo -e "  Config guide    : ${CYAN}${INSTRUCTIONS_FILE}${NC}"
echo
echo -e "  OpenClaw was installed under the openclaw user. Switch to that user first:"
echo -e "  ${CYAN}  su - openclaw${NC}"
echo
echo -e "  ${YELLOW}NEXT STEP:${NC} Run the interactive onboarding wizard:"
echo -e "  ${CYAN}  openclaw onboard --install-daemon${NC}"
echo
echo -e "  Then read the guide for full configuration instructions:"
echo -e "  ${CYAN}  cat ${INSTRUCTIONS_FILE}${NC}"
echo

sudo truncate -s 0 /etc/motd

sudo wall "The installation of OpenClaw is complete. Switch to openclaw user (su - openclaw) and see /home/openclaw/openclaw_configuration_guide.txt for more details"

sudo rm -f /home/install_openclaw.sh

sudo rm -f /home/openclaw/install_openclaw.sh

sudo history -c 2>/dev/null || true