# The checks that were only ever running on a laptop.
#
# Before this file, CI ran Playwright (chromium-desktop) and the dependency audit — and nothing
# else. `cargo test` (40 tests), the frontend vitest suite (5 files, including the offline
# upload-queue and auth-token logic), svelte-check, and the e2e typecheck were all green on a
# developer's machine and gated NOTHING. A check that only ever runs locally is not running.
#
# In .github/workflows/ because Gitea Actions scans it too (see audit.yml). Rust is installed
# explicitly: the common Gitea runner images ship Node and Docker, not cargo.
name: Checks

on:
  pull_request:
  push:
    branches: [main]

jobs:
  backend:
    name: Backend — cargo test + clippy + fmt
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust toolchain
        run: |
          if ! command -v cargo > /dev/null; then
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
            echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
          fi
          rustup component add clippy rustfmt

      - uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            backend/target
          key: cargo-${{ hashFiles('backend/Cargo.lock') }}
          restore-keys: cargo-

      # SQLx runs its queries against a live database at TEST time (see backend/tests/), so the
      # DB-backed tests need one. The pure unit tests don't care, but starting it unconditionally
      # keeps the job simple and honest about what it covers.
      - name: Start Postgres
        run: |
          docker run -d --name ci-pg -p 5432:5432 \
            -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=eventsnap_ci \
            postgres:16-alpine
          for _ in $(seq 1 30); do
            docker exec ci-pg pg_isready -U postgres > /dev/null 2>&1 && break
            sleep 1
          done

      - name: Test
        working-directory: ./backend
        env:
          DATABASE_URL: postgres://postgres:postgres@localhost:5432/eventsnap_ci
        # `#[sqlx::test]` creates a fresh database per test and opens its own pool; run at unbounded
        # parallelism against a default `max_connections=100` Postgres, a full suite can exhaust the
        # server's connection slots and fail with PoolTimedOut — a pure infra flake, not a real
        # failure. Cap the concurrency so the gate stays trustworthy on a loaded runner.
        run: cargo test --all-features -- --test-threads=8

      - name: Clippy
        working-directory: ./backend
        run: cargo clippy --all-targets -- -D warnings

      - name: Format
        working-directory: ./backend
        run: cargo fmt --check

  frontend:
    name: Frontend — vitest + svelte-check
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: 'frontend/package-lock.json'

      - name: Install deps
        working-directory: ./frontend
        run: npm ci || npm install

      - name: Unit tests
        working-directory: ./frontend
        run: npm run test:unit

      - name: svelte-check
        working-directory: ./frontend
        run: npx svelte-check --threshold error

      - name: ESLint
        working-directory: ./frontend
        run: npm run lint

      - name: Prettier
        working-directory: ./frontend
        run: npm run format:check

  export-viewer:
    name: Keepsake viewer — builds, self-contained, committed artifact in sync
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'
          cache-dependency-path: 'frontend/export-viewer/package-lock.json'

      - name: Install deps
        working-directory: ./frontend/export-viewer
        run: npm ci || npm install

      # Two things nothing else in CI covered, both of which ship a broken keepsake silently.
      #
      # 1. The build's own self-contained guard (`inlineThemeFonts`) is the only thing standing
      #    between an added theme asset and a viewer that reaches for files on the guest's disk.
      #    It is a build-time `this.error`, so it only fires when somebody runs this build — and
      #    no workflow, Dockerfile or script did. It could sit disarmed indefinitely.
      #
      # 2. `backend/static/export-viewer/index.html` is COMMITTED and compiled into the binary with
      #    `include_dir!`. A viewer source change merged without a manual rebuild ships the stale
      #    artifact, and nothing anywhere would say so. `git diff --exit-code` is the check.
      - name: Build the standalone viewer
        working-directory: ./frontend/export-viewer
        run: npm run build

      - name: Committed artifact matches a clean rebuild
        run: |
          if ! git diff --exit-code -- backend/static/export-viewer/; then
            echo "::error::backend/static/export-viewer/ is out of date with frontend/export-viewer/."
            echo "Run 'npm run build' in frontend/export-viewer and commit the result."
            exit 1
          fi

  e2e-typecheck:
    name: E2E — typecheck + lint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - name: Install deps
        working-directory: ./e2e
        run: npm install
      # Playwright TRANSPILES specs without typechecking them, so a type error in a spec is
      # invisible until the assertion it guards silently does the wrong thing at runtime.
      - name: tsc --noEmit
        working-directory: ./e2e
        run: npx tsc --noEmit

      - name: ESLint
        working-directory: ./e2e
        run: npm run lint

      - name: Prettier
        working-directory: ./e2e
        run: npm run format:check
