# Hold Slayer — single image: FastAPI process that also serves the built
# SvelteKit dashboard at "/". One container, four surfaces (REST/WS/MCP/dash).
#
# pjsua2 is deliberately NOT built here — it is not pip-installable (compiled
# from pjproject) and the media pipeline degrades to documented stub mode
# without it. That is correct for a mock-SIP dev deploy (USE_MOCK_SIP=true);
# /health honestly reports the mock engine as "degraded". Building real media
# is a separate, deliberate piece of work.

# Stage 1: build the SvelteKit dashboard → dashboard/build/ (SPA, static).
# dashboard/build and dashboard/node_modules are gitignored, so build fresh
# here rather than copying a stale working-tree artifact.
FROM node:22-alpine AS dashboard
WORKDIR /dashboard
COPY dashboard/package.json dashboard/package-lock.json ./
RUN npm ci
COPY dashboard/ ./
RUN npm run build

# Stage 2: runtime. The app runs FROM SOURCE at /app (not purely from
# site-packages): db/database.py locates alembic.ini via
# Path(__file__).parent.parent, and main.py/config.py are loose top-level
# modules — both require the source tree layout under the working dir. An
# editable install puts the deps + entry points in place while keeping /app/db,
# /app/config.py, /app/alembic.ini resolving to the real files.
FROM python:3.12-slim
WORKDIR /app

# build-essential: some deps compile from source (no manylinux wheel).
# curl: required for the compose healthcheck (GET /health).
RUN apt-get update \
    && apt-get install -y --no-install-recommends build-essential curl \
    && rm -rf /var/lib/apt/lists/*

# Install dependencies first (better layer caching) using just the manifest,
# then the source. -e keeps the package importable from /app so alembic.ini
# and the loose modules resolve correctly at runtime.
COPY pyproject.toml README.md ./
COPY . .
# Bring in the freshly built dashboard (overwrites any stale gitignored copy).
COPY --from=dashboard /dashboard/build ./dashboard/build

RUN pip install --no-cache-dir -e . \
    && apt-get purge -y build-essential && apt-get autoremove -y

EXPOSE 21081

# Structured logs by default in the container: the host's Alloy agent reads
# stdout and ships it to Loki, where text lines arrive as an unqueryable blob.
# Overridable (LOG_FORMAT=text) for interactive `docker run` debugging.
ENV LOG_FORMAT=json

# Migrations run in the app's own init_db() on boot (db/database.py), so no
# separate `alembic upgrade` here. Bind host/port from the same env vars
# pydantic-settings reads (HOST/PORT) so configured values and the actual bind
# cannot drift. Deploy sets PORT=21081 (image default 8000 collides with other
# host-net services on triton).
CMD ["sh", "-c", "uvicorn main:app --host ${HOST:-0.0.0.0} --port ${PORT:-21081}"]
