# ============================================================================
# Claude Code Agents UI - Dockerfile
# Combines Ngxba/claude-code-agents-ui frontend with Claude Code CLI runtime
# ============================================================================

# --- Build Stage ---
FROM node:20-alpine AS builder

WORKDIR /app

# Install build dependencies
RUN apk add --no-cache git

# Clone the Claude Code Agents UI repository
RUN git clone --depth 1 https://github.com/Ngxba/claude-code-agents-ui.git .

# Install dependencies (prefer bun if lockfile present, fallback to npm)
RUN if [ -f bun.lockb ]; then \
        npm install -g bun && bun install --frozen-lockfile; \
    else \
        npm install; \
    fi

# Build the Nuxt application
RUN npm run build 2>/dev/null || npx nuxt build

# --- Production Stage ---
FROM node:20-alpine

WORKDIR /app

# Install runtime dependencies
RUN apk add --no-cache \
    python3 \
    py3-pip \
    git \
    curl \
    wget \
    bash \
    vim \
    nano \
    build-base \
    openssh-client \
    ca-certificates \
    tini \
    jq

# Install Claude Code CLI
RUN npm install -g @anthropic-ai/claude-code

# Install Python tools for agent execution
RUN pip3 install --no-cache-dir --break-system-packages \
    requests \
    python-dotenv \
    pydantic \
    fastapi \
    uvicorn

# Copy built Nuxt application from builder
COPY --from=builder /app/.output /app/.output
COPY --from=builder /app/package.json /app/package.json

# Create non-root user for security
RUN addgroup -g 1000 claude && \
    adduser -D -u 1000 -G claude claude

# Create necessary directories
RUN mkdir -p /workspace /root/.claude && \
    chown -R claude:claude /workspace && \
    chown -R root:root /root/.claude

# Set app ownership
RUN chown -R claude:claude /app

# ----------------------------------------------------------------------------
# Entrypoint: bootstraps Claude auth then starts the UI
# ----------------------------------------------------------------------------
# Auth strategy (in priority order):
#   1. If ANTHROPIC_API_KEY is set → write a minimal credentials file so the
#      Claude Code CLI recognises the key without needing an interactive login.
#   2. If a credentials file was volume-mounted at /root/.claude/.credentials.json
#      already (e.g. from a docker volume) → use it as-is.
#   3. Fall through to the UI which will surface an auth error to the user.
# ----------------------------------------------------------------------------
RUN cat > /entrypoint.sh << 'ENTRYPOINT_EOF'
#!/bin/sh
set -e

CLAUDE_DIR="${CLAUDE_CONFIG_DIR:-/root/.claude}"
CREDS_FILE="${CLAUDE_DIR}/.credentials.json"

echo "[entrypoint] Claude config dir: ${CLAUDE_DIR}"
mkdir -p "${CLAUDE_DIR}"

# --- Bootstrap auth from ANTHROPIC_API_KEY ---
if [ -n "${ANTHROPIC_API_KEY}" ]; then
    if [ ! -f "${CREDS_FILE}" ]; then
        echo "[entrypoint] Writing credentials from ANTHROPIC_API_KEY..."
        # Claude Code CLI accepts a credentials file with an apiKey field as
        # an alternative to OAuth.  This is the non-interactive equivalent of
        # running `claude auth login` with an API key.
        cat > "${CREDS_FILE}" << CREDS_EOF
{
  "claudeAiOauth": null,
  "apiKey": "${ANTHROPIC_API_KEY}"
}
CREDS_EOF
        chmod 600 "${CREDS_FILE}"
        echo "[entrypoint] Credentials written successfully."
    else
        echo "[entrypoint] Credentials file already exists, skipping write."
    fi
else
    echo "[entrypoint] WARNING: ANTHROPIC_API_KEY not set."
    echo "[entrypoint]   Set it in your .env file or via 'docker run -e ANTHROPIC_API_KEY=...'."
    echo "[entrypoint]   The UI will load but Claude Code execution will fail without auth."
fi

# --- Verify Claude CLI can see the key ---
if claude auth status 2>/dev/null | grep -q "Logged in\|api key"; then
    echo "[entrypoint] Claude CLI auth: OK"
else
    echo "[entrypoint] Claude CLI auth: not authenticated (will use ANTHROPIC_API_KEY at runtime)"
fi

# --- Start the Nuxt application ---
echo "[entrypoint] Starting Claude Code Agents UI on port 3000..."
exec node /app/.output/server/index.mjs
ENTRYPOINT_EOF

RUN chmod +x /entrypoint.sh

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
    CMD curl -f http://localhost:3000 || exit 1

EXPOSE 3000

# Use tini for proper signal handling
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/entrypoint.sh"]
