# Claude sandbox image: Claude CLI + Node.js + Python + claude-proxy
# Supports both amd64 and arm64 architectures
# Base: Ubuntu 24.04 LTS
ARG REGISTRY=yaoapp
FROM ${REGISTRY}/sandbox-base:latest

USER root

# Use MIT mirror (USA) for ARM64 - in case base image cache is old
RUN sed -i 's|http://ports.ubuntu.com/ubuntu-ports|http://mirrors.mit.edu/ubuntu-ports|g' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || \
    sed -i 's|http://ports.ubuntu.com/ubuntu-ports|http://mirrors.mit.edu/ubuntu-ports|g' /etc/apt/sources.list 2>/dev/null || true

# Python 3.12 (default in Ubuntu 24.04) - install first as Node.js depends on it
RUN apt-get update && apt-get install -y \
    python3 \
    python3-pip \
    python3-venv \
    && rm -rf /var/lib/apt/lists/* \
    && ln -sf /usr/bin/python3 /usr/bin/python

# Node.js 22 LTS (automatically detects architecture)
# Run apt-get update again to refresh package lists after nodesource setup
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
    && apt-get update \
    && apt-get install -y nodejs \
    && rm -rf /var/lib/apt/lists/*

# GitHub CLI (gh) for repository operations
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
    && chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
    && echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
    && apt-get update \
    && apt-get install -y gh \
    && rm -rf /var/lib/apt/lists/*

# npm global packages directory for sandbox user
RUN mkdir -p /home/sandbox/.npm-global && \
    chown -R sandbox:sandbox /home/sandbox/.npm-global

USER sandbox

# Configure npm to use user directory
RUN npm config set prefix '/home/sandbox/.npm-global'
ENV PATH="/home/sandbox/.npm-global/bin:${PATH}"

# Install Claude CLI
RUN npm install -g @anthropic-ai/claude-code || \
    echo "Claude CLI installation skipped (may not be available yet)"

# Create Claude CLI configuration for auto-approve all operations
# This is CRITICAL for non-interactive sandbox usage
# The --dangerously-skip-permissions flag alone is not enough;
# we also need the settings.json to fully bypass permission prompts
RUN mkdir -p /home/sandbox/.claude && \
    cat > /home/sandbox/.claude/settings.json << 'EOF'
{
  "permissions": {
    "defaultMode": "bypassPermissions",
    "allow": ["*"],
    "deny": []
  }
}
EOF

USER root

# Install claude-proxy (architecture-specific binary)
ARG TARGETARCH
COPY claude-proxy-${TARGETARCH} /usr/local/bin/claude-proxy
RUN chmod +x /usr/local/bin/claude-proxy

# Create claude-proxy startup script
RUN cat > /usr/local/bin/start-proxy << 'SCRIPT'
#!/bin/bash
# Claude Proxy startup script
# Usage: start-proxy [options]
# Options are passed directly to claude-proxy

LOG_DIR="${WORKSPACE:-/workspace}"
LOG_FILE="${LOG_DIR}/proxy.log"

# Ensure log directory exists
mkdir -p "$LOG_DIR" 2>/dev/null || true

# Default environment variables (can be overridden)
export CLAUDE_PROXY_PORT="${CLAUDE_PROXY_PORT:-3456}"

# Start proxy with logging
exec /usr/local/bin/claude-proxy -v -l "$LOG_FILE" "$@"
SCRIPT
RUN chmod +x /usr/local/bin/start-proxy

# Create claude-run wrapper for easy usage (manual mode)
RUN cat > /usr/local/bin/claude-run << 'SCRIPT'
#!/bin/bash
# Claude CLI wrapper with proxy auto-start
# Usage: claude-run [claude options] "prompt"
#
# Environment variables:
#   CLAUDE_PROXY_BACKEND  - Backend API URL (required)
#   CLAUDE_PROXY_API_KEY  - Backend API Key (required)
#   CLAUDE_PROXY_MODEL    - Backend model name (required)
#   CLAUDE_PROXY_PORT     - Proxy port (default: 3456)
#   WORKSPACE             - Working directory (default: /workspace)

set -e

# Check required environment variables
if [ -z "$CLAUDE_PROXY_BACKEND" ]; then
    echo "Error: CLAUDE_PROXY_BACKEND is not set"
    echo "Example: export CLAUDE_PROXY_BACKEND=https://ark.cn-beijing.volces.com/api/v3/chat/completions"
    exit 1
fi

if [ -z "$CLAUDE_PROXY_API_KEY" ]; then
    echo "Error: CLAUDE_PROXY_API_KEY is not set"
    exit 1
fi

if [ -z "$CLAUDE_PROXY_MODEL" ]; then
    echo "Error: CLAUDE_PROXY_MODEL is not set"
    echo "Example: export CLAUDE_PROXY_MODEL=glm-4-7-251222"
    exit 1
fi

PORT="${CLAUDE_PROXY_PORT:-3456}"
WORKSPACE="${WORKSPACE:-/workspace}"
LOG_FILE="${WORKSPACE}/proxy.log"

# Check if proxy is already running
if curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
    echo "Proxy already running on port $PORT"
else
    echo "Starting claude-proxy..."
    mkdir -p "$WORKSPACE" 2>/dev/null || true
    nohup /usr/local/bin/claude-proxy -v -l "$LOG_FILE" > /dev/null 2>&1 &
    
    # Wait for proxy to start
    for i in {1..10}; do
        if curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
            echo "Proxy started successfully"
            break
        fi
        sleep 0.5
    done
    
    if ! curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
        echo "Error: Failed to start proxy"
        exit 1
    fi
fi

# Set Claude CLI environment
export ANTHROPIC_BASE_URL="http://127.0.0.1:${PORT}"
export ANTHROPIC_API_KEY="dummy"

# Change to workspace directory
cd "$WORKSPACE"

# Run Claude CLI with all arguments
exec claude "$@"
SCRIPT
RUN chmod +x /usr/local/bin/claude-run

# Create start-claude-proxy script for programmatic use (called by Yao)
# Config is read from /tmp/.yao/proxy.json (NOT /workspace/ for security - api_key/secrets hidden from user)
RUN cat > /usr/local/bin/start-claude-proxy << 'SCRIPT'
#!/bin/bash
# Start claude-proxy from config file or environment variables
# Config file: /tmp/.yao/proxy.json (secure location, not visible to user file manager)
# Format: {"backend": "...", "api_key": "...", "model": "...", "options": {...}, "secrets": {...}}

CONFIG_FILE="/tmp/.yao/proxy.json"
LOG_FILE="${WORKSPACE:-/workspace}/proxy.log"
PORT="${CLAUDE_PROXY_PORT:-3456}"

# Try to read from config file first
if [ -f "$CONFIG_FILE" ]; then
    BACKEND=$(jq -r '.backend // empty' "$CONFIG_FILE" 2>/dev/null)
    API_KEY=$(jq -r '.api_key // empty' "$CONFIG_FILE" 2>/dev/null)
    MODEL=$(jq -r '.model // empty' "$CONFIG_FILE" 2>/dev/null)
    # Read extra options as JSON string (e.g., {"thinking":{"type":"enabled"}})
    OPTIONS=$(jq -c '.options // empty' "$CONFIG_FILE" 2>/dev/null)
    
    if [ -n "$BACKEND" ]; then
        export CLAUDE_PROXY_BACKEND="$BACKEND"
    fi
    if [ -n "$API_KEY" ]; then
        export CLAUDE_PROXY_API_KEY="$API_KEY"
    fi
    if [ -n "$MODEL" ]; then
        export CLAUDE_PROXY_MODEL="$MODEL"
    fi
    # Only set options if it's a valid non-empty JSON object
    if [ -n "$OPTIONS" ] && [ "$OPTIONS" != "null" ] && [ "$OPTIONS" != "" ]; then
        export CLAUDE_PROXY_OPTIONS="$OPTIONS"
    fi
    
    # Export secrets as environment variables for Claude CLI to use
    # e.g., {"GITHUB_TOKEN": "ghp_xxx"} -> export GITHUB_TOKEN=ghp_xxx
    SECRETS=$(jq -c '.secrets // empty' "$CONFIG_FILE" 2>/dev/null)
    if [ -n "$SECRETS" ] && [ "$SECRETS" != "null" ] && [ "$SECRETS" != "" ] && [ "$SECRETS" != "{}" ]; then
        # Parse each key-value pair and export
        for key in $(echo "$SECRETS" | jq -r 'keys[]' 2>/dev/null); do
            value=$(echo "$SECRETS" | jq -r --arg k "$key" '.[$k]' 2>/dev/null)
            if [ -n "$value" ] && [ "$value" != "null" ]; then
                export "$key"="$value"
            fi
        done
    fi
fi

# Check if we have the required config
if [ -z "$CLAUDE_PROXY_BACKEND" ] || [ -z "$CLAUDE_PROXY_API_KEY" ] || [ -z "$CLAUDE_PROXY_MODEL" ]; then
    echo "Error: Missing proxy configuration"
    echo "Either set environment variables or create $CONFIG_FILE"
    exit 1
fi

# Check if already running
if curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
    echo "claude-proxy already running"
    exit 0
fi

# Start proxy with environment variables explicitly passed
mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null || true
nohup env \
    CLAUDE_PROXY_BACKEND="$CLAUDE_PROXY_BACKEND" \
    CLAUDE_PROXY_API_KEY="$CLAUDE_PROXY_API_KEY" \
    CLAUDE_PROXY_MODEL="$CLAUDE_PROXY_MODEL" \
    CLAUDE_PROXY_OPTIONS="$CLAUDE_PROXY_OPTIONS" \
    /usr/local/bin/claude-proxy -v -l "$LOG_FILE" > /dev/null 2>&1 &

# Wait for startup
for i in {1..20}; do
    if curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
        echo "claude-proxy started on port $PORT"
        exit 0
    fi
    sleep 0.5
done

echo "Error: claude-proxy failed to start"
exit 1
SCRIPT
RUN chmod +x /usr/local/bin/start-claude-proxy

# Create entrypoint script
# Note: claude-proxy is started on-demand by Yao (via start-claude-proxy)
# or manually by user (via claude-run)
RUN cat > /usr/local/bin/entrypoint.sh << 'SCRIPT'
#!/bin/bash
# Container entrypoint
# claude-proxy is NOT auto-started here - it's started by:
# 1. Yao's sandbox executor (writes config to .claude-proxy.json, calls start-claude-proxy)
# 2. Manual usage via claude-run command
# 3. Direct invocation of start-claude-proxy

WORKSPACE="${WORKSPACE:-/workspace}"
PORT="${CLAUDE_PROXY_PORT:-3456}"
ENV_FILE="/tmp/claude-proxy-env"

# If proxy env vars are set AND proxy is not running, start it
# This supports docker run -e CLAUDE_PROXY_BACKEND=... usage
if [ -n "$CLAUDE_PROXY_BACKEND" ] && [ -n "$CLAUDE_PROXY_API_KEY" ] && [ -n "$CLAUDE_PROXY_MODEL" ]; then
    if ! curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
        /usr/local/bin/start-claude-proxy
    fi
    
    # Write env vars to a file that can be sourced
    if curl -s "http://127.0.0.1:${PORT}/health" > /dev/null 2>&1; then
        echo "export ANTHROPIC_BASE_URL=http://127.0.0.1:${PORT}" > "$ENV_FILE"
        echo "export ANTHROPIC_API_KEY=dummy" >> "$ENV_FILE"
        chmod 644 "$ENV_FILE"
    fi
fi

# Execute the command passed to docker run
exec "$@"
SCRIPT
RUN chmod +x /usr/local/bin/entrypoint.sh

# Create a wrapper that sources the env file
RUN cat > /usr/local/bin/claude-env << 'SCRIPT'
#!/bin/bash
# Source claude-proxy environment if available
if [ -f /tmp/claude-proxy-env ]; then
    source /tmp/claude-proxy-env
fi
exec "$@"
SCRIPT
RUN chmod +x /usr/local/bin/claude-env

# Add sourcing to global bashrc so docker exec gets the vars
RUN echo '[ -f /tmp/claude-proxy-env ] && source /tmp/claude-proxy-env' >> /etc/bash.bashrc

USER sandbox

# Verify installations
RUN node --version && npm --version && python3 --version && \
    claude --version || true && \
    claude-proxy --help 2>&1 | head -1 || true

WORKDIR /workspace

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["sleep", "infinity"]
