name: CI

permissions:
  contents: read

on:
  pull_request:
  push:
    branches: [main]

jobs:
  scan_ruby:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      security-events: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Scan for common Rails security vulnerabilities using static analysis
        continue-on-error: true
        run: bin/brakeman --no-pager -f sarif -o brakeman.sarif.json

      - name: Upload SARIF to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: brakeman.sarif.json

  scan_js:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Scan for security vulnerabilities in JavaScript dependencies
        run: bin/importmap audit

  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Lint code for consistent style
        run: bin/rubocop -f github

  frontend:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Bun
        uses: oven-sh/setup-bun@v2

      - name: Install JavaScript dependencies
        run: bun install --frozen-lockfile

      - name: Run Svelte type checks
        run: bun run check:svelte

      - name: Run Svelte formatting checks
        run: bun run format:svelte:check

  zeitwerk:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Run Rails Zeitwerk check
        run: bin/rails zeitwerk:check

  test:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:16-alpine
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: app_test

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Run tests
        env:
          RAILS_ENV: test
          TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
          PGHOST: localhost
          PGUSER: postgres
          PGPASSWORD: postgres
        run: |
          bin/rails db:create RAILS_ENV=test
          bin/rails db:schema:load RAILS_ENV=test
          bin/rails test

      - name: Ensure Swagger docs are up to date
        env:
          RAILS_ENV: test
          TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
          PGHOST: localhost
          PGUSER: postgres
          PGPASSWORD: postgres
        run: |
          bin/rails rswag:specs:swaggerize
          git diff --exit-code swagger/v1/swagger.yaml

  test_system:
    runs-on: ubuntu-latest

    services:
      postgres:
        image: postgres:16-alpine
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
        env:
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: app_test

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: .ruby-version
          bundler-cache: true

      - name: Set up Bun
        uses: oven-sh/setup-bun@v2

      # Pin Chrome to version 133 to avoid flaky system test failures.
      # Chrome 134+ has a known bug causing intermittent Selenium/Capybara failures
      # where session paths don't update correctly after visit() calls.
      # See: https://github.com/teamcapybara/capybara/issues/2800
      # Remove this pin once the upstream issue is resolved.
      - name: Setup Chrome
        id: setup-chrome
        uses: browser-actions/setup-chrome@latest
        with:
          chrome-version: 133
          install-chromedriver: true

      - name: Install JavaScript dependencies
        run: bun install --frozen-lockfile

      - name: Pre-build Vite assets for test
        run: bin/vite build
        env:
          RAILS_ENV: test

      - name: Run system tests
        env:
          RAILS_ENV: test
          TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/app_test
          PGHOST: localhost
          PGUSER: postgres
          PGPASSWORD: postgres
          CHROME_BIN: ${{ steps.setup-chrome.outputs.chrome-path }}
          CHROMEDRIVER_BIN: ${{ steps.setup-chrome.outputs.chromedriver-path }}
        run: |
          bin/rails db:create RAILS_ENV=test
          bin/rails db:schema:load RAILS_ENV=test
          bin/rails test:system

      - name: Keep screenshots from failed system tests
        uses: actions/upload-artifact@v7
        if: failure()
        with:
          name: screenshots
          path: ${{ github.workspace }}/tmp/screenshots
          if-no-files-found: ignore
