# --- Build stage: install dependencies ---
FROM python:3.12-slim AS builder

ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv

# Install dependencies first (cached layer — only reruns when pyproject.toml/uv.lock change).
# `--extra flight-duckdb-only` pulls in pyarrow + ob-flight-extension + the 8 vendor
# drivers so /v1/query/execute can actually run SQL against the baked-in
# DuckDB demo file (and any other configured vendor).
#
# The vendor driver workspace members live under drivers/, so we copy
# their pyproject.toml manifests before the sync so uv can resolve the
# workspace graph. The actual driver source is copied alongside src/
# below.
COPY pyproject.toml uv.lock README.md ./
COPY drivers/ drivers/
RUN uv sync --no-dev --no-install-project --frozen --extra flight-duckdb-only

# Copy source and install the project itself
COPY src/ src/
COPY schema/ schema/
COPY osi-obml/osi_obml_converter.py osi-obml/
COPY osi-obml/osi-schema.json osi-obml/
RUN uv sync --no-dev --no-editable --frozen --extra flight-duckdb-only

# --- Runtime stage: minimal image ---
FROM python:3.12-slim

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1

WORKDIR /app

# Install IANA tzdata so Python's zoneinfo can resolve names like
# Europe/Berlin. python:3.12-slim has no /usr/share/zoneinfo, and without
# it ZoneInfo("Europe/Berlin") raises ZoneInfoNotFoundError — the timezone
# resolver then silently falls back to UTC. Belt-and-suspenders alongside
# the tzdata Python dep.
RUN apt-get update \
    && apt-get install -y --no-install-recommends tzdata \
    && rm -rf /var/lib/apt/lists/*

# Create non-root user
RUN groupadd -r app && useradd -r -g app -d /app -s /sbin/nologin app

# Copy installed virtualenv from builder
COPY --from=builder --chown=app:app /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"

# Copy schema (needed at runtime for validation)
COPY --from=builder --chown=app:app /app/schema schema/

# Copy OSI converter (needed at runtime for /convert endpoints)
COPY --from=builder --chown=app:app /app/osi-obml osi-obml/

# Bake the public-demo dataset and matching OBML model into the image so
# the Cloud Run service can answer /v1/query/execute without external
# infra. The .duckdb file is pre-generated by scripts/build_demo_duckdb.py
# before the docker build (see deploy-gcloud.sh).
COPY --chown=app:app examples/orionbelt_1_commerce.yaml   /app/data/orionbelt_1_commerce.yaml
COPY --chown=app:app examples/orionbelt_1_commerce.duckdb /app/data/orionbelt_1_commerce.duckdb

USER app

# Cloud Run injects PORT (default 8080)
ENV PORT=8080 \
    API_SERVER_HOST=0.0.0.0 \
    LOG_LEVEL=INFO \
    LOG_FORMAT=json \
    DISABLE_SESSION_LIST=true \
    EXPOSE_API_DOCS=true \
    EXPOSE_OPENAPI_SCHEMA=true \
    DB_VENDOR=duckdb \
    DUCKDB_DATABASE=/app/data/orionbelt_1_commerce.duckdb \
    MODEL_DIR=/app/data \
    MODEL_FILE=orionbelt_1_commerce.yaml

EXPOSE ${PORT}

# Health check for local Docker / Compose (Cloud Run uses its own probes)
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen(f'http://localhost:{__import__(\"os\").environ[\"PORT\"]}/health')"

# Single worker — Cloud Run scales by adding container instances, not workers
CMD ["sh", "-c", "uvicorn orionbelt.api.app:create_app --factory --host 0.0.0.0 --port $PORT --log-level info --proxy-headers --forwarded-allow-ips='*' --no-access-log"]
