name: Pipeline

on:
  push:
    branches: [master]
    tags: ['v*']
  pull_request:
    branches: [master]

jobs:

  # ── UI ────────────────────────────────────────────────────────────────────────

  ui-test:
    name: UI Tests
    runs-on: ubuntu-latest
    container:
      image: node:22-bullseye
    steps:
      - uses: actions/checkout@v4

      - name: Install Firefox
        run: apt-get update -qq && apt-get install -y --no-install-recommends firefox-esr

      - name: Cache node_modules
        uses: actions/cache@v3
        with:
          path: ui/node_modules
          key: npm-${{ hashFiles('ui/package-lock.json') }}
          restore-keys: npm-

      - name: Install dependencies
        run: npm ci
        working-directory: ui

      - name: Run tests
        run: FIREFOX_BIN=/usr/bin/firefox-esr npx ng test --watch=false
        working-directory: ui

  ui-lint:
    name: UI Lint
    runs-on: ubuntu-latest
    container:
      image: node:22-bullseye
    steps:
      - uses: actions/checkout@v4

      - name: Cache node_modules
        uses: actions/cache@v3
        with:
          path: ui/node_modules
          key: npm-${{ hashFiles('ui/package-lock.json') }}
          restore-keys: npm-

      - name: Install dependencies
        run: npm ci
        working-directory: ui

      - name: Run ESLint
        run: npm run lint
        working-directory: ui

  # ── API ───────────────────────────────────────────────────────────────────────

  api-unit:
    name: API Unit Tests
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/astral-sh/uv:python3.12-bookworm
    steps:
      - name: Install Node (for JS actions)
        run: |
          apt-get update -qq
          apt-get install -y --no-install-recommends nodejs ca-certificates curl

      - uses: actions/checkout@v4

      - name: Cache uv store
        uses: actions/cache@v3
        with:
          path: /root/.cache/uv
          key: uv-${{ hashFiles('api/uv.lock') }}
          restore-keys: uv-

      - name: Install dependencies
        run: uv sync --group dev
        working-directory: api

      - name: Run unit tests
        run: uv run pytest tests/unit/ -q
        working-directory: api
        env:
          DATABASE_URL: postgresql+asyncpg://u:p@localhost/db
          S3_ENDPOINT_URL: http://localhost:9000
          S3_BUCKET_NAME: test
          S3_ACCESS_KEY_ID: key
          S3_SECRET_ACCESS_KEY: secret
          S3_REGION: us-east-1
          API_BASE_URL: http://localhost:8000
          JWT_SECRET_KEY: test-secret
          OWNER_USERNAME: testowner
          OWNER_PASSWORD: testpass

  api-lint:
    name: API Lint
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/astral-sh/uv:python3.12-bookworm
    steps:
      - name: Install Node (for JS actions)
        run: |
          apt-get update -qq
          apt-get install -y --no-install-recommends nodejs ca-certificates curl

      - uses: actions/checkout@v4

      - name: Run Ruff
        run: uvx ruff check .
        working-directory: api

  api-integration:
    name: API Integration Tests
    runs-on: ubuntu-latest
    container:
      image: ghcr.io/astral-sh/uv:python3.12-bookworm
    services:
      postgres:
        image: postgres:16
        env:
          POSTGRES_USER: reactbin
          POSTGRES_PASSWORD: reactbin
          POSTGRES_DB: reactbin_test
        options: >-
          --health-cmd pg_isready
          --health-interval 5s
          --health-timeout 5s
          --health-retries 10
      minio:
        image: bitnamilegacy/minio:2025.7.23-debian-12-r5
        env:
          MINIO_ROOT_USER: minioadmin
          MINIO_ROOT_PASSWORD: minioadmin
          MINIO_DEFAULT_BUCKETS: reactbin-test
        options: >-
          --health-cmd "mc ready local || exit 1"
          --health-interval 5s
          --health-timeout 5s
          --health-retries 10
    steps:
      - name: Install Node and curl (for JS actions and mc)
        run: |
          apt-get update -qq
          apt-get install -y --no-install-recommends nodejs ca-certificates curl

      - uses: actions/checkout@v4

      - name: Cache uv store
        uses: actions/cache@v3
        with:
          path: /root/.cache/uv
          key: uv-${{ hashFiles('api/uv.lock') }}
          restore-keys: uv-

      - name: Install dependencies
        run: uv sync --group dev
        working-directory: api

      - name: Run integration tests
        run: uv run pytest tests/integration/ -q
        working-directory: api
        env:
          TEST_DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@postgres/reactbin_test
          DATABASE_URL: postgresql+asyncpg://reactbin:reactbin@postgres/reactbin_test
          S3_ENDPOINT_URL: http://minio:9000
          S3_BUCKET_NAME: reactbin-test
          S3_ACCESS_KEY_ID: minioadmin
          S3_SECRET_ACCESS_KEY: minioadmin
          S3_REGION: us-east-1
          API_BASE_URL: http://localhost:8000
          JWT_SECRET_KEY: test-secret
          OWNER_USERNAME: testowner
          OWNER_PASSWORD: testpass

  # ── Image builds (tag-only, gated on all jobs) ────────────────────────────────

  build-api:
    name: Build & Push API Image
    runs-on: ubuntu-latest
    needs: [ui-test, ui-lint, api-unit, api-lint, api-integration]
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ${{ vars.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.REGISTRY_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: ./api
          file: ./api/Dockerfile.prod
          push: true
          tags: |
            ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/reactbin-api:${{ github.ref_name }}
            ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/reactbin-api:latest

  build-ui:
    name: Build & Push UI Image
    runs-on: ubuntu-latest
    needs: [ui-test, ui-lint, api-unit, api-lint, api-integration]
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ${{ vars.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.REGISTRY_TOKEN }}

      - uses: docker/build-push-action@v6
        with:
          context: ./ui
          file: ./ui/Dockerfile.prod
          push: true
          tags: |
            ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/reactbin-ui:${{ github.ref_name }}
            ${{ vars.REGISTRY }}/${{ vars.REPOSITORY }}/reactbin-ui:latest