# Static browser assets are architecture-neutral; avoid emulating Node for ARM builds.
FROM --platform=$BUILDPLATFORM node:24-trixie-slim AS ui-builder
WORKDIR /app/ui
COPY ui/package*.json ./
RUN npm ci
COPY ui/ ./
RUN npm run build

# Same upstream release, rebuilt with patched Go and reviewed dependency pins.
FROM golang:1.27.3-trixie AS importer
ENV GOMAXPROCS=2 GOFLAGS=-p=2 GOTOOLCHAIN=local
WORKDIR /src
RUN curl --fail --location --retry 2 https://codeload.github.com/simulot/immich-go/tar.gz/3b8a9a071f68ac47f7f055ed8186c829de0d150b -o /tmp/source.tar.gz \
 && echo "f238a9ffc321d336285684ce521093619e43a018edf10d81928e71d25e6e858f  /tmp/source.tar.gz" | sha256sum -c - \
 && tar -xzf /tmp/source.tar.gz --strip-components=1
COPY deploy/importer/go.mod deploy/importer/go.sum ./
COPY deploy/importer/MODIFICATIONS.txt ./BRIDGE-MODIFICATIONS.txt
COPY deploy/importer/bridge_report.go deploy/importer/bridge_report_test.go ./internal/assettracker/
RUN sed -i '/fmt.Println(uc.app.FileProcessor().GenerateReport())/a\fmt.Println(string(uc.app.FileProcessor().Tracker().BridgeReport()))\nuc.app.FileProcessor().Tracker().BridgeAffectedItems()' app/upload/run.go \
 && sed -i '/func (uc \*UpCmd) resumeJobs(_ context.Context) error {/a\if !uc.client.PauseImmichBackgroundJobs { return nil }' app/upload/run.go
RUN go mod download && go mod verify
RUN --mount=type=cache,target=/root/.cache/go-build go test ./internal/assettracker -run TestBridgeReport && CGO_ENABLED=0 go build -mod=readonly -trimpath -tags timetzdata \
    -ldflags="-s -w -X github.com/simulot/immich-go/app.Version=0.32.0-bridge.4" -o /out/immich-go . \
 && /out/immich-go version \
 && cp LICENSE /out/LICENSE.immich-go

# Ship dependency source and build instructions with the matching importer source.
FROM importer AS importer-source-package
RUN go mod vendor
COPY Dockerfile /package/Bridge.Dockerfile
COPY deploy/importer/BUILDING.md /package/BUILDING.md
RUN mkdir -p /package/source && cp -a /src/. /package/source/ \
 && tar --sort=name --mtime=@0 --owner=0 --group=0 --numeric-owner \
    -czf /out/immich-go-0.32.0-bridge.4-source.tar.gz -C /package . \
 && cd /out && sha256sum immich-go-0.32.0-bridge.4-source.tar.gz > immich-go-0.32.0-bridge.4-source.tar.gz.sha256

FROM scratch AS importer-source
COPY --from=importer-source-package /out/immich-go-0.32.0-bridge.4-source.tar.gz /out/immich-go-0.32.0-bridge.4-source.tar.gz.sha256 /

FROM golang:1.27.3-trixie AS backend-builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY cmd/ ./cmd/
COPY internal/ ./internal/
RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=1 go build -trimpath -o /out/immich-bridge ./cmd/server \
 && CGO_ENABLED=0 go build -trimpath -o /out/bridge-runner ./cmd/runner \
 && CGO_ENABLED=1 go build -trimpath -o /out/bridge-processor ./cmd/processor

FROM backend-builder AS backend-tests
COPY --from=importer /out/immich-go /usr/local/bin/immich-go
ENV IMMICH_GO_TEST_BINARY=/usr/local/bin/immich-go
RUN test -z "$(gofmt -l cmd internal)"
RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=1 go test -timeout 120s ./cmd/... ./internal/... && go vet ./cmd/... ./internal/... \
 && go test -c -o /out/runner.test ./internal/runner

# Exercise tus-js-client against the actual Go upload server; never silently skip
# this integration just because the Go build image does not normally include Node.
FROM backend-builder AS backend-client-tests
COPY --from=ui-builder /usr/local/bin/node /usr/local/bin/node
COPY --from=ui-builder /app/ui/node_modules ./ui/node_modules
COPY ui/tests/tus-resume.mjs ./ui/tests/tus-resume.mjs
RUN --mount=type=cache,target=/root/.cache/go-build node --version && test -d ui/node_modules/tus-js-client && go test -v -count=1 -timeout 120s -run ^TestTusBrowserLibraryCanAbortAndResume$ ./internal/api

FROM backend-tests AS runner-race-tests
RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=1 go test -race -timeout 120s ./internal/runner

FROM backend-tests AS backend-race-tests
RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=1 go test -race -timeout 120s -run 'Test(AdvancedImport|TaskNotification|TaskAnalysis|TaskImport|ActualImporterShutdown|KeyRevokedDuringProcessing|TwoSignedInUsers|DistinctUsers|Administrator|CollectionDelete|PrivateDiagnostics(Redaction|Bounds|Remote|Collection))' ./internal/api && go test -race -timeout 120s ./internal/auth ./internal/configuration ./internal/diagnostics ./internal/importoptions ./internal/notifications
RUN --mount=type=cache,target=/root/.cache/go-build CGO_ENABLED=1 go test -race -timeout 120s ./internal/runner

# Cache scanner tools independently of application edits, with bounded memory.
FROM golang:1.27.3-trixie AS security-tools
ENV GOMAXPROCS=2 GOFLAGS=-p=2
WORKDIR /scanner
# gosec 2.29 needs the compatible x/tools importer for Go 1.27 export data.
RUN go mod init bridge-security-tools \
    && go get github.com/securego/gosec/v2/cmd/gosec@v2.29.0 golang.org/x/tools@v0.52.0
RUN --mount=type=cache,target=/root/.cache/go-build go build -o /out/gosec github.com/securego/gosec/v2/cmd/gosec \
    && GOBIN=/out go install golang.org/x/vuln/cmd/govulncheck@v1.9.0

# Focused checks for a changed importer; do not rerun unrelated application suites.
FROM backend-builder AS importer-compatibility-tests
COPY --from=importer /out/immich-go /usr/local/bin/immich-go
ENV IMMICH_GO_TEST_BINARY=/usr/local/bin/immich-go
RUN --mount=type=cache,target=/root/.cache/go-build go test -race -count=1 -timeout 120s -run 'Test(ActualPinnedImmichGo|ActualImporterShutdown|StructuredImport)' ./internal/api \
 && go test -c -o /out/runner.test ./internal/runner

FROM importer AS importer-vulnerability-scan
COPY --from=security-tools /out/govulncheck /usr/local/bin/govulncheck
RUN set +e; govulncheck -mode=binary -json /out/immich-go > /out/importer-vulns.json; status=$?; set -e; test "$status" = 0 -o "$status" = 3

FROM scratch AS importer-security-report
COPY --from=importer-vulnerability-scan /out/importer-vulns.json /

# Findings are reviewed explicitly, not suppressed.
FROM backend-builder AS backend-security-scan
ENV GOMAXPROCS=2 GOFLAGS=-p=2
COPY --from=security-tools /out/gosec /out/govulncheck /usr/local/bin/
RUN set +e; gosec -concurrency=1 -fmt=json -out=/gosec.json ./cmd/... ./internal/...; status=$?; set -e; test "$status" = 0 -o "$status" = 1
RUN set +e; govulncheck -json ./cmd/... ./internal/... > /govulncheck.json; status=$?; set -e; test "$status" = 0 -o "$status" = 3

FROM scratch AS security-reports
COPY --from=backend-security-scan /gosec.json /govulncheck.json /

FROM debian:trixie-slim AS processor
ENV LANG=C LC_ALL=C LANGUAGE=
COPY LICENSE /usr/share/licenses/immich-bridge/LICENSE
RUN groupadd --gid 10001 bridge && useradd --uid 10001 --gid bridge --no-create-home bridge
COPY --from=backend-builder /out/bridge-processor /usr/local/bin/bridge-processor
COPY --from=importer /out/immich-go /usr/local/bin/immich-go
COPY --from=importer /out/LICENSE.immich-go /usr/share/licenses/immich-go/LICENSE
COPY --from=importer /src/BRIDGE-MODIFICATIONS.txt /usr/share/licenses/immich-go/MODIFICATIONS.txt
USER 10001:10001
ENTRYPOINT ["/usr/local/bin/bridge-processor"]

FROM debian:trixie-slim AS runner
ENV LANG=C LC_ALL=C LANGUAGE=
COPY LICENSE /usr/share/licenses/immich-bridge/LICENSE
COPY --from=backend-builder /out/bridge-runner /usr/local/bin/bridge-runner
ENTRYPOINT ["/usr/local/bin/bridge-runner"]

FROM debian:trixie-slim AS runtime
ENV LANG=C LC_ALL=C LANGUAGE=
COPY LICENSE /usr/share/licenses/immich-bridge/LICENSE
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates tzdata && rm -rf /var/lib/apt/lists/* \
    && groupadd --gid 10001 bridge && useradd --uid 10001 --gid bridge --no-create-home bridge \
    && install -d -o bridge -g bridge -m 0700 /data /staging
WORKDIR /app
COPY --from=backend-builder /out/immich-bridge ./immich-bridge
COPY --from=ui-builder /app/ui/dist ./ui/dist
USER 10001:10001
ENV DB_PATH=/data/bridge.db UPLOAD_DIR=/staging/uploads UI_DIR=/app/ui/dist BRIDGE_LISTEN_ADDRESS=:8080
EXPOSE 8080
CMD ["./immich-bridge"]
