# ============================================================
# SmallClaw / LocalClaw – Dockerfile
# ============================================================
# Multi-stage build:
#   1. builder  – compiles TypeScript → dist/
#   2. runtime  – lean production image with Playwright + Tesseract deps

# ── Stage 1: Builder ────────────────────────────────────────
FROM node:20-slim AS builder

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci

COPY tsconfig.json ./
COPY src/ ./src/

RUN npm run build

# ── Stage 2: Runtime ────────────────────────────────────────
FROM node:20-slim AS runtime

# System deps: Playwright/Chromium + Tesseract OCR + ffmpeg (for voice)
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    curl \
    wget \
    ffmpeg \
    fonts-liberation \
    libatk-bridge2.0-0 \
    libatk1.0-0 \
    libcairo2 \
    libcups2 \
    libdbus-1-3 \
    libdrm2 \
    libexpat1 \
    libgbm1 \
    libglib2.0-0 \
    libgtk-3-0 \
    libnspr4 \
    libnss3 \
    libpango-1.0-0 \
    libpangocairo-1.0-0 \
    libx11-6 \
    libx11-xcb1 \
    libxcb1 \
    libxcomposite1 \
    libxdamage1 \
    libxext6 \
    libxfixes3 \
    libxrandr2 \
    libxrender1 \
    libxss1 \
    libxtst6 \
    xdg-utils \
    tesseract-ocr \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Production deps only
COPY package.json package-lock.json ./
RUN npm ci --omit=dev

# Install Playwright browser binaries
RUN npx playwright install chromium --with-deps 2>/dev/null || true

# Install Piper TTS binary + Korean voice model (from neurlang — rhasspy repo returns 404 for Korean)
RUN ARCH=$(dpkg --print-architecture) && \
    if [ "$ARCH" = "amd64" ]; then PIPER_ARCH="x86_64"; \
    elif [ "$ARCH" = "arm64" ]; then PIPER_ARCH="aarch64"; \
    elif [ "$ARCH" = "armhf" ]; then PIPER_ARCH="armv7l"; \
    else PIPER_ARCH="$ARCH"; fi && \
    cd /tmp && \
    curl -L "https://github.com/rhasspy/piper/releases/download/2023.11.14-2/piper_linux_${PIPER_ARCH}.tar.gz" -o piper.tar.gz && \
    tar xzf piper.tar.gz && \
    cp piper/piper /usr/local/bin/piper && \
    chmod +x /usr/local/bin/piper && \
    cp piper/libespeak-ng.so* /usr/local/lib/ && \
    cp piper/libonnxruntime.so* /usr/local/lib/ && \
    cp piper/libpiper_phonemize.so* /usr/local/lib/ && \
    cp piper/espeak-ng /usr/local/lib/ && \
    cp -r piper/espeak-ng-data /usr/local/lib/ && \
    ldconfig && \
    rm -rf piper piper.tar.gz && \
    mkdir -p /usr/local/share/piper-voices && \
    curl -L "https://huggingface.co/neurlang/piper-onnx-kss-korean/resolve/main/piper-kss-korean.onnx" \
    -o /usr/local/share/piper-voices/ko_KR-kss-medium.onnx && \
    curl -L "https://huggingface.co/neurlang/piper-onnx-kss-korean/raw/main/piper-kss-korean.onnx.json" \
    -o /usr/local/share/piper-voices/ko_KR-kss-medium.onnx.json

# Install whisper.cpp (build from source — no pre-built Linux binary)
RUN apt-get update && apt-get install -y --no-install-recommends cmake git build-essential && \
    cd /tmp && \
    git clone https://github.com/ggml-org/whisper.cpp.git && \
    cd whisper.cpp && \
    cmake -B build && \
    cmake --build build --config Release -j$(nproc) && \
    cp build/bin/whisper-cli /usr/local/bin/whisper-cli && \
    rm -rf /tmp/whisper.cpp && \
    apt-get remove -y git build-essential && \
    apt-get autoremove -y && \
    rm -rf /var/lib/apt/lists/* && \
    mkdir -p /usr/local/share/whisper-models && \
    curl -L "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-base.bin" \
    -o /usr/local/share/whisper-models/ggml-base.bin

# Compiled app from builder
COPY --from=builder /app/dist ./dist

# Static web UI
COPY web-ui/ ./web-ui/

# Data directories (overridden by volumes in compose)
RUN mkdir -p /data/workspace /data/logs /root/.localclaw

# ── Environment defaults ─────────────────────────────────────
# These are overridden by docker-compose.yml / -e flags.
# Provider: ollama | lm_studio | llama_cpp | openai | openai_codex
ENV NODE_ENV=production \
    DOCKER_CONTAINER=true \
    SMALLCLAW_DATA_DIR=/data \
    SMALLCLAW_WORKSPACE_DIR=/data/workspace \
    GATEWAY_PORT=18789 \
    GATEWAY_HOST=0.0.0.0 \
    PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright \
    \
    # Active provider
    SMALLCLAW_PROVIDER=ollama \
    \
    # Ollama
    OLLAMA_HOST=http://ollama:11434 \
    \
    # LM Studio (host machine via host.docker.internal)
    LM_STUDIO_ENDPOINT=http://host.docker.internal:1234 \
    LM_STUDIO_API_KEY="" \
    LM_STUDIO_MODEL="" \
    \
    # llama.cpp (host machine via host.docker.internal)
    LLAMA_CPP_ENDPOINT=http://host.docker.internal:8080 \
    LLAMA_CPP_MODEL="" \
    \
    # OpenAI
    OPENAI_API_KEY="" \
    OPENAI_MODEL=gpt-4o \
    \
    # OpenAI Codex OAuth (tokens live in mounted ~/.localclaw volume)
    CODEX_MODEL=gpt-5.3-codex \
    \
    # Voice (Piper TTS + Whisper STT model paths)
    PIPER_MODEL_PATH=/usr/local/share/piper-voices/ko_KR-kss-medium.onnx \
    PIPER_CONFIG_PATH=/usr/local/share/piper-voices/ko_KR-kss-medium.onnx.json \
    WHISPER_MODEL_PATH=/usr/local/share/whisper-models/ggml-base.bin

EXPOSE 18789

HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
    CMD curl -f http://localhost:18789/health || exit 1

CMD ["node", "dist/cli/index.js", "gateway"]
