# syntax=docker/dockerfile:1

# SwyxWeb als ein Container: Das React-Frontend wird gebaut, in die statischen
# Ressourcen des Backends gelegt und zusammen mit ihm in ein Jar gepackt.
# Ausgeliefert wird am Ende alles über den einen Port des Backends (8080).
#
# Der eingebaute SwyxTray-Mock (/ws und /api/mock/**) läuft NICHT mit: seine
# Bohnen hängen am Spring-Profil "mock", und das setzt dieses Image nicht.
#
# Die beiden Build-Stufen laufen bewusst auf $BUILDPLATFORM, also nativ auf dem
# bauenden Rechner: JS-Bundle und Jar sind architekturunabhängig. Nur die
# Laufzeitstufe nutzt die Zielarchitektur.

# ---------------------------------------------------------------------------
# 1. Frontend bauen (Vite -> frontend/dist)
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM node:22-alpine AS frontend
WORKDIR /build

# Erst die Abhängigkeiten, damit diese Schicht im Cache bleibt, solange sich
# package.json/package-lock.json nicht ändern.
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci

COPY frontend/ ./
# VITE_WS_URL nur setzen, wenn die Adresse fest ins Bundle soll; im Normalfall
# kommt sie zur Laufzeit aus /api/config (siehe README).
ARG VITE_WS_URL
RUN npm run build

# ---------------------------------------------------------------------------
# 2. Backend bauen (Spring Boot 4.1, Java 21) inkl. Frontend als static/
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM maven:3.9-eclipse-temurin-21 AS backend
WORKDIR /build

# Abhängigkeiten vorab auflösen – eigene Schicht, unabhängig vom Quelltext.
COPY backend/pom.xml ./
RUN --mount=type=cache,target=/root/.m2 \
    mvn -B -q dependency:go-offline

COPY backend/src ./src
COPY --from=frontend /build/dist/ ./src/main/resources/static/

RUN --mount=type=cache,target=/root/.m2 \
    mvn -B -DskipTests clean package \
 && cp target/*.jar /build/app.jar

# ---------------------------------------------------------------------------
# 3. Whisper-Modell einmalig ins Image laden, unabhängig von der Zielarchitektur.
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM python:3.12-slim-bookworm AS whisper-model
ENV HF_HUB_DISABLE_TELEMETRY=1
RUN pip install --no-cache-dir huggingface-hub==2.3.0
ARG WHISPER_MODEL_REPO=mobiuslabsgmbh/faster-whisper-large-v3-turbo
ARG WHISPER_MODEL_REVISION=0a363e9161cbc7ed1431c9597a8ceaf0c4f78fcf
RUN python -c 'import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ["WHISPER_MODEL_REPO"], revision=os.environ["WHISPER_MODEL_REVISION"], local_dir="/models/whisper", allow_patterns=["*.json", "model.bin", "vocabulary.*", "README.md"])' \
 && rm -rf /models/whisper/.cache

# ---------------------------------------------------------------------------
# 4. Java + lokaler Whisper-Worker (glibc für CTranslate2/PyAV statt Alpine).
# ---------------------------------------------------------------------------
FROM eclipse-temurin:21-jre-noble AS runtime

RUN apt-get update \
 && apt-get install -y --no-install-recommends python3 python3-venv libgomp1 curl tini \
 && rm -rf /var/lib/apt/lists/* \
 && python3 -m venv /opt/whisper
ENV PATH="/opt/whisper/bin:$PATH"
COPY transcription/requirements.txt /app/transcription/requirements.txt
RUN pip install --no-cache-dir -r /app/transcription/requirements.txt && pip check

# Nicht als root laufen.
RUN groupadd --gid 10001 swyx \
 && useradd --uid 10001 --gid swyx --create-home swyx \
 && mkdir -p /data/transcriptions \
 && chown -R swyx:swyx /data
WORKDIR /app

COPY --from=backend --chown=swyx:swyx /build/app.jar ./app.jar
COPY --from=whisper-model /models/ ./models/
COPY transcription/service.py transcription/summary.py ./transcription/
COPY --chmod=755 docker/entrypoint.sh ./entrypoint.sh

USER swyx
EXPOSE 8080
VOLUME ["/data/transcriptions"]

# Adresse der SwyxTray-App zur Laufzeit überschreibbar (Spring Relaxed Binding):
#   -e APP_WEBSOCKET_HOST=127.0.0.1 -e APP_WEBSOCKET_PORT=17654
#   -e APP_WEBSOCKET_PATH=/ws -e APP_WEBSOCKET_SECURE=false
#
# SPRING_PROFILES_ACTIVE bleibt bewusst leer – der SwyxTray-Mock bliebe sonst
# beim Ausrollen erreichbar. Für eine Vorführung ohne Telefonanlage lässt er
# sich einzeln einschalten: -e SPRING_PROFILES_ACTIVE=mock
ENV JAVA_OPTS="-XX:MaxRAMPercentage=25.0" \
    APP_TRANSCRIPTION_BASE_URL=http://127.0.0.1:8765 \
    WHISPER_MODEL_PATH=/app/models/whisper \
    WHISPER_DATA_DIR=/data/transcriptions \
    WHISPER_THREADS=4 \
    PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    HF_HUB_OFFLINE=1 \
    HF_HUB_DISABLE_TELEMETRY=1 \
    TOKENIZERS_PARALLELISM=false

HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \
  CMD curl -fsS --max-time 2 http://127.0.0.1:8080/api/config >/dev/null \
   && curl -fsS --max-time 2 http://127.0.0.1:8765/health >/dev/null || exit 1

ENTRYPOINT ["/usr/bin/tini", "--", "/app/entrypoint.sh"]
