#!/usr/bin/env bash
# OpenClaw One-Click Installer for macOS / Linux
# Usage: curl -fsSL https://openclaw.cn/scripts/install.sh | bash
# Website: https://openclaw.cn

set -euo pipefail

VERSION="2.0.0"
INSTALL_DIR="$HOME/.openclaw"
LOG_FILE="$INSTALL_DIR/install.log"
OPENCLAW_PORT="${OPENCLAW_PORT:-18789}"
NPM_MIRROR="https://registry.npmmirror.com"
NODE_VERSION="22"

# Colors
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
BLUE='\033[0;34m'; CYAN='\033[0;36m'; NC='\033[0m'

# ============================================================================
# Output helpers
# ============================================================================

log_info()    { echo -e "  ${CYAN}[i]${NC} $*"; }
log_ok()      { echo -e "  ${GREEN}[OK]${NC} $*"; }
log_warn()    { echo -e "  ${YELLOW}[!]${NC} $*"; }
log_err()     { echo -e "  ${RED}[X]${NC} $*"; }
log_step()    { echo ""; echo -e "  ${CYAN}--- $* ---${NC}"; }

cmd_exists()  { command -v "$1" &>/dev/null; }

ask_yes_no() {
    local prompt="$1" default="${2:-y}"
    local hint="(Y/n)"
    [[ "$default" == "n" ]] && hint="(y/N)"
    read -rp "$prompt $hint: " answer
    answer="${answer:-$default}"
    [[ "$answer" =~ ^[Yy] ]]
}

# ============================================================================
# Cleanup on error
# ============================================================================

cleanup() {
    local code=$?
    if [[ $code -ne 0 ]]; then
        log_err "Installation failed (exit code: $code)"
        log_info "Log file: $LOG_FILE"
        log_info "Help: https://openclaw.cn/community.html"
    fi
}
trap cleanup EXIT

# ============================================================================
# Welcome
# ============================================================================

show_welcome() {
    clear 2>/dev/null || true
    echo ""
    echo -e "  ${CYAN}+=========================================================+"
    echo -e "  |                                                         |"
    echo -e "  |         OpenClaw One-Click Installer v${VERSION}              |"
    echo -e "  |         https://openclaw.cn                             |"
    echo -e "  |                                                         |"
    echo -e "  +=========================================================${NC}"
    echo ""
}

# ============================================================================
# OS Detection
# ============================================================================

detect_os() {
    log_step "Detecting system"

    OS="$(uname -s)"
    ARCH="$(uname -m)"

    case "$OS" in
        Darwin) OS_NAME="macOS" ;;
        Linux)  OS_NAME="Linux" ;;
        *)      log_err "Unsupported OS: $OS"; exit 1 ;;
    esac

    log_info "OS: $OS_NAME ($ARCH)"

    # Check disk space (need at least 500MB)
    local free_mb
    if [[ "$OS" == "Darwin" ]]; then
        free_mb=$(df -m / | awk 'NR==2{print $4}')
    else
        free_mb=$(df -m / | awk 'NR==2{print $4}')
    fi
    log_info "Free disk: ${free_mb}MB"
    if [[ "$free_mb" -lt 500 ]]; then
        log_err "Need at least 500MB free disk space"
        exit 1
    fi

    log_ok "System check passed"
}

# ============================================================================
# Node.js: Check -> Install -> Verify
# ============================================================================

check_node() {
    if ! cmd_exists node; then return 1; fi
    local ver
    ver=$(node -v 2>/dev/null | sed 's/v//')
    local major
    major=$(echo "$ver" | cut -d. -f1)
    if [[ "$major" -ge "$NODE_VERSION" ]]; then
        log_ok "Node.js v$ver"
        return 0
    else
        log_warn "Node.js v$ver found, but v${NODE_VERSION}+ required"
        return 1
    fi
}

reload_shell_path() {
    # Source common profile files to pick up newly installed binaries
    for f in "$HOME/.bashrc" "$HOME/.bash_profile" "$HOME/.zshrc" "$HOME/.profile"; do
        [[ -f "$f" ]] && source "$f" 2>/dev/null || true
    done
    # Also check nvm
    export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
    [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh" 2>/dev/null || true
}

install_node_nvm() {
    log_info "Installing Node.js $NODE_VERSION via nvm..."

    # Install nvm if not present
    if ! cmd_exists nvm; then
        log_info "Installing nvm..."
        # Try China mirror first
        local nvm_url="https://openclaw.cn/scripts/nvm-install.sh"
        if ! curl -fsSL "$nvm_url" | bash 2>>"$LOG_FILE"; then
            nvm_url="https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh"
            curl -fsSL "$nvm_url" | bash 2>>"$LOG_FILE" || return 1
        fi
        export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
        [[ -s "$NVM_DIR/nvm.sh" ]] && source "$NVM_DIR/nvm.sh"
    fi

    if cmd_exists nvm; then
        # Use China mirror for node download
        export NVM_NODEJS_ORG_MIRROR="https://npmmirror.com/mirrors/node"
        nvm install "$NODE_VERSION" 2>>"$LOG_FILE" || {
            # Fallback to official mirror
            unset NVM_NODEJS_ORG_MIRROR
            nvm install "$NODE_VERSION" 2>>"$LOG_FILE" || return 1
        }
        nvm use "$NODE_VERSION" 2>>"$LOG_FILE" || true
        nvm alias default "$NODE_VERSION" 2>>"$LOG_FILE" || true
        return 0
    fi
    return 1
}

install_node_brew() {
    if ! cmd_exists brew; then return 1; fi
    log_info "Installing Node.js $NODE_VERSION via Homebrew..."
    brew install "node@$NODE_VERSION" 2>>"$LOG_FILE" || return 1

    # node@22 is keg-only, add to PATH
    local brew_prefix
    brew_prefix="$(brew --prefix)"
    local node_bin="$brew_prefix/opt/node@$NODE_VERSION/bin"
    if [[ -d "$node_bin" ]]; then
        export PATH="$node_bin:$PATH"
    fi
    return 0
}

install_node_pkg_manager() {
    # Linux: try apt, dnf, yum
    if cmd_exists apt-get; then
        log_info "Installing Node.js $NODE_VERSION via apt..."
        # Use China mirror for NodeSource
        curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash - 2>>"$LOG_FILE" || return 1
        sudo apt-get install -y nodejs 2>>"$LOG_FILE" || return 1
        return 0
    fi
    if cmd_exists dnf; then
        log_info "Installing Node.js $NODE_VERSION via dnf..."
        curl -fsSL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | sudo bash - 2>>"$LOG_FILE" || return 1
        sudo dnf install -y nodejs 2>>"$LOG_FILE" || return 1
        return 0
    fi
    if cmd_exists yum; then
        log_info "Installing Node.js $NODE_VERSION via yum..."
        curl -fsSL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | sudo bash - 2>>"$LOG_FILE" || return 1
        sudo yum install -y nodejs 2>>"$LOG_FILE" || return 1
        return 0
    fi
    return 1
}

install_node_binary() {
    log_info "Downloading Node.js $NODE_VERSION binary directly..."
    local arch_name
    case "$ARCH" in
        x86_64|amd64)  arch_name="x64" ;;
        aarch64|arm64) arch_name="arm64" ;;
        armv7l)        arch_name="armv7l" ;;
        *)             log_err "Unsupported arch: $ARCH"; return 1 ;;
    esac

    local os_name
    case "$OS" in
        Darwin) os_name="darwin" ;;
        Linux)  os_name="linux" ;;
    esac

    local filename="node-v22.16.0-${os_name}-${arch_name}.tar.xz"
    local url="https://npmmirror.com/mirrors/node/v22.16.0/$filename"
    local tmp_dir="/tmp/openclaw-node-install"

    mkdir -p "$tmp_dir"

    # Try China mirror first
    if ! curl -fsSL "$url" -o "$tmp_dir/$filename" 2>>"$LOG_FILE"; then
        url="https://nodejs.org/dist/v22.16.0/$filename"
        log_info "China mirror failed, trying official..."
        curl -fsSL "$url" -o "$tmp_dir/$filename" 2>>"$LOG_FILE" || return 1
    fi

    log_info "Extracting..."
    tar -xJf "$tmp_dir/$filename" -C "$tmp_dir" 2>>"$LOG_FILE" || return 1

    local node_dir="$tmp_dir/node-v22.16.0-${os_name}-${arch_name}"
    if [[ -d "$node_dir" ]]; then
        # Install to /usr/local or ~/.local
        if [[ -w /usr/local/bin ]]; then
            sudo cp -r "$node_dir/bin/"* /usr/local/bin/ 2>/dev/null || cp -r "$node_dir/bin/"* /usr/local/bin/
            sudo cp -r "$node_dir/lib/"* /usr/local/lib/ 2>/dev/null || true
        else
            mkdir -p "$HOME/.local/bin"
            cp -r "$node_dir/bin/"* "$HOME/.local/bin/"
            mkdir -p "$HOME/.local/lib"
            cp -r "$node_dir/lib/"* "$HOME/.local/lib/" 2>/dev/null || true
            export PATH="$HOME/.local/bin:$PATH"
        fi
    fi

    rm -rf "$tmp_dir"
    return 0
}

ensure_node() {
    log_step "Checking Node.js"

    # Check existing
    if check_node; then return 0; fi

    # Reload shell config and re-check
    reload_shell_path
    if check_node; then return 0; fi

    # Need to install - try methods in order
    log_step "Installing Node.js $NODE_VERSION"

    # macOS: prefer Homebrew, fallback to nvm, then binary
    if [[ "$OS" == "Darwin" ]]; then
        install_node_brew && reload_shell_path && check_node && return 0
        install_node_nvm && reload_shell_path && check_node && return 0
        install_node_binary && check_node && return 0
    fi

    # Linux: try package manager, nvm, then binary
    if [[ "$OS" == "Linux" ]]; then
        install_node_pkg_manager && check_node && return 0
        install_node_nvm && reload_shell_path && check_node && return 0
        install_node_binary && check_node && return 0
    fi

    log_err "All Node.js installation methods failed."
    log_info "Please install Node.js 22+ manually: https://nodejs.org/en/download"
    exit 1
}

# ============================================================================
# Install OpenClaw via npm (with China mirror + multiple retries)
# ============================================================================

install_openclaw() {
    log_step "Installing OpenClaw"

    # Configure git to use HTTPS (avoid SSH key issues)
    git config --global url."https://github.com/".insteadOf "ssh://git@github.com/" 2>/dev/null || true
    git config --global url."https://github.com/".insteadOf "git@github.com:" 2>/dev/null || true

    local npm_cmd="npm"
    local success=false

    # Suppress noisy output
    export NPM_CONFIG_LOGLEVEL="error"
    export NPM_CONFIG_UPDATE_NOTIFIER="false"
    export NPM_CONFIG_FUND="false"
    export NPM_CONFIG_AUDIT="false"
    export NODE_LLAMA_CPP_SKIP_DOWNLOAD="1"

    # Try 1: China mirror
    log_info "Installing via China mirror (npmmirror.com)..."
    if $npm_cmd install -g openclaw@latest --registry "$NPM_MIRROR" 2>>"$LOG_FILE"; then
        success=true
    fi

    # Try 2: Official registry
    if [[ "$success" != "true" ]]; then
        log_warn "China mirror failed, trying official npm..."
        if $npm_cmd install -g openclaw@latest 2>>"$LOG_FILE"; then
            success=true
        fi
    fi

    # Try 3: With sudo (Linux permission issues)
    if [[ "$success" != "true" && "$OS" == "Linux" ]]; then
        log_warn "Retrying with sudo..."
        if sudo $npm_cmd install -g openclaw@latest --registry "$NPM_MIRROR" 2>>"$LOG_FILE"; then
            success=true
        elif sudo $npm_cmd install -g openclaw@latest 2>>"$LOG_FILE"; then
            success=true
        fi
    fi

    # Try 4: Force flag
    if [[ "$success" != "true" ]]; then
        log_warn "Retrying with --force..."
        if $npm_cmd install -g openclaw@latest --force 2>>"$LOG_FILE"; then
            success=true
        fi
    fi

    if [[ "$success" != "true" ]]; then
        log_err "npm install failed after all attempts"
        log_info "Try manually: npm install -g openclaw@latest"
        log_info "Log: $LOG_FILE"
        exit 1
    fi

    # Ensure openclaw is on PATH
    if ! cmd_exists openclaw; then
        local npm_bin
        npm_bin=$(npm bin -g 2>/dev/null || echo "")
        if [[ -n "$npm_bin" && -f "$npm_bin/openclaw" ]]; then
            export PATH="$npm_bin:$PATH"
        fi
    fi

    if cmd_exists openclaw; then
        local ver
        ver=$(openclaw --version 2>/dev/null || echo "installed")
        log_ok "OpenClaw $ver"
    else
        log_ok "OpenClaw installed (restart terminal if 'openclaw' not found)"
    fi
}

# ============================================================================
# Configure: non-interactive remote mode + open access
# ============================================================================

configure_and_start() {
    if ! cmd_exists openclaw; then
        # Try to find it
        local npm_bin
        npm_bin=$(npm bin -g 2>/dev/null || echo "")
        [[ -n "$npm_bin" && -f "$npm_bin/openclaw" ]] && export PATH="$npm_bin:$PATH"
    fi
    if ! cmd_exists openclaw; then
        log_warn "openclaw not found on PATH"
        log_info "Restart terminal and run: openclaw onboard"
        return
    fi

    # Pre-create config with remote mode + open access
    log_step "Writing config (remote mode, open access)"
    local config_dir="$HOME/.openclaw"
    local config_file="$config_dir/openclaw.json"
    mkdir -p "$config_dir"

    if [[ ! -f "$config_file" ]]; then
        local token
        token=$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 32)
        cat > "$config_file" << CONF
{
  "gateway": {
    "port": ${OPENCLAW_PORT},
    "bind": "0.0.0.0",
    "auth": { "token": "${token}" }
  },
  "channels": {
    "defaults": {
      "dmPolicy": "open",
      "groupPolicy": "open"
    }
  },
  "agents": {
    "defaults": {
      "model": { "primary": "openrouter/auto" }
    }
  }
}
CONF
        log_ok "Config written (remote mode, open access, token auto-generated)"
    else
        log_info "Config already exists, keeping current settings"
    fi

    # Run onboard to finalize
    log_step "Finalizing setup"
    if openclaw onboard --non-interactive --mode remote --install-daemon --skip-health --accept-risk 2>>"$LOG_FILE"; then
        log_ok "Setup finalized"
    else
        log_info "Onboard skipped (config already written, gateway can start)"
    fi

    # Start gateway
    log_step "Starting Gateway"
    # Try systemd service first
    if cmd_exists systemctl; then
        if systemctl --user is-enabled openclaw-gateway 2>/dev/null | grep -q enabled; then
            systemctl --user restart openclaw-gateway 2>/dev/null || true
            log_ok "Gateway daemon restarted via systemd"
        else
            # Try gateway install (creates systemd unit)
            if openclaw gateway install 2>>"$LOG_FILE"; then
                log_ok "Gateway daemon installed (auto-start on boot)"
            else
                # Fallback: start in background
                nohup openclaw gateway >> "$LOG_FILE" 2>&1 &
                log_ok "Gateway started in background (PID: $!)"
            fi
        fi
    else
        # No systemd (macOS or minimal Linux)
        nohup openclaw gateway >> "$LOG_FILE" 2>&1 &
        log_ok "Gateway started in background (PID: $!)"
    fi

    # Wait for gateway
    log_info "Waiting for gateway to be ready..."
    local waited=0
    while [[ $waited -lt 20 ]]; do
        if ss -tlnp 2>/dev/null | grep -q ":${OPENCLAW_PORT} " || \
           lsof -i ":${OPENCLAW_PORT}" -sTCP:LISTEN 2>/dev/null | grep -q LISTEN || \
           curl -sf "http://localhost:${OPENCLAW_PORT}/healthz" >/dev/null 2>&1; then
            log_ok "Gateway running at http://localhost:${OPENCLAW_PORT}"
            return
        fi
        sleep 2
        waited=$((waited + 2))
    done
    log_info "Gateway may still be starting: http://localhost:${OPENCLAW_PORT}"
}

# ============================================================================
# Success
# ============================================================================

show_done() {
    echo ""
    echo -e "  ${GREEN}+=========================================================${NC}"
    echo -e "  ${GREEN}|         Installation Complete!                          ${NC}"
    echo -e "  ${GREEN}+=========================================================${NC}"
    echo ""
    echo -e "  Gateway UI:  ${CYAN}http://localhost:${OPENCLAW_PORT}${NC}"
    echo ""
    echo -e "  Quick start:"
    echo -e "    ${BLUE}openclaw --version${NC}        Check version"
    echo -e "    ${BLUE}openclaw gateway status${NC}   Check gateway"
    echo -e "    ${BLUE}openclaw onboard${NC}          Re-run setup wizard"
    echo -e "    ${BLUE}openclaw doctor${NC}           Diagnose issues"
    echo ""
    echo -e "  Docs: ${BLUE}https://openclaw.cn${NC}"
    echo ""
}

# ============================================================================
# Main
# ============================================================================

main() {
    mkdir -p "$(dirname "$LOG_FILE")"
    echo "--- Install started $(date) ---" >> "$LOG_FILE"

    show_welcome
    detect_os
    ensure_node
    install_openclaw
    configure_and_start
    show_done

    log_ok "All done!"
}

main "$@"
