name: CI

on:
  push:
  pull_request:

env:
  CARGO_TERM_COLOR: always

jobs:
  generate-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.generate.outputs.matrix }}
    steps:
      - id: generate
        uses: mmastrac/mmm-matrix@v1
        with:
          input: |
            rust-toolchain: stable
            job: [test]
            feature_combo: [default, all-features, no-default-features]
            cargo_args:
              $match:
                "this.feature_combo == 'default'": ""
                "this.feature_combo == 'all-features'": "--all-features"
                "this.feature_combo == 'no-default-features'": "--no-default-features"
            label:
              linux:
                os: ubuntu-latest
              macos:
                os: macos-latest
              windows:
                os: windows-latest
          config: |
            github: ${{ toJSON(github) }}

  test:
    name: ${{ matrix.label }} / ${{ matrix.job }} / ${{ matrix.feature_combo }} (${{ matrix.rust-toolchain }})
    runs-on: ${{ matrix.os }}
    needs: generate-matrix
    strategy:
      fail-fast: false
      matrix:
        include: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}

    steps:
      - uses: actions/checkout@v6

      - name: Install Rust toolchain (${{ matrix.rust-toolchain }})
        uses: actions-rust-lang/setup-rust-toolchain@v1
        with:
          toolchain: ${{ matrix.rust-toolchain }}
          components: clippy

      - name: Install wget (Windows)
        if: ${{ runner.os == 'Windows' }}
        shell: bash
        run: |
          choco install -y wget > /dev/null || echo "choco failed"
          wget --version

      - name: Install pwsh (Linux)
        if: ${{ runner.os == 'Linux' }}
        shell: bash
        run: |
          set -euxo pipefail
          sudo apt-get update
          sudo apt-get install -y powershell
          command -v pwsh >/dev/null 2>&1 && pwsh -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion'

      # Docker httpbin is only practical on Linux GitHub runners; use Waitress elsewhere.
      - name: Set up Python (httpbin on Windows or macOS)
        if: ${{ runner.os == 'Windows' || runner.os == 'macOS' }}
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Start httpbin (Waitress, Windows)
        if: ${{ runner.os == 'Windows' }}
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          python -m pip install -U pip
          python -m pip install httpbin waitress
          $port = 8080
          $listen = "127.0.0.1:$port"
          $proc = Start-Process -FilePath python -ArgumentList @(
            '-m', 'waitress', "--listen=$listen", 'httpbin:app'
          ) -WindowStyle Hidden -PassThru
          Add-Content -Path $env:GITHUB_ENV -Value "SHELL_DOWNLOAD_HTTPBIN=http://127.0.0.1:$port"
          for ($i = 0; $i -lt 90; $i++) {
            try {
              Invoke-WebRequest -Uri "http://127.0.0.1:$port/get" -UseBasicParsing -TimeoutSec 3 | Out-Null
              exit 0
            } catch {
              Start-Sleep -Seconds 1
            }
          }
          throw "httpbin did not become ready in time (waitress pid=$($proc.Id))"

      - name: Start httpbin (Waitress, macOS)
        if: ${{ runner.os == 'macOS' }}
        shell: bash
        run: |
          set -euo pipefail
          python -m pip install -U pip
          python -m pip install httpbin waitress
          PORT=8080
          python -m waitress --listen="127.0.0.1:${PORT}" httpbin:app &
          echo "SHELL_DOWNLOAD_HTTPBIN=http://127.0.0.1:${PORT}" >> "$GITHUB_ENV"
          for _ in {1..90}; do
            if curl -sfS "http://127.0.0.1:${PORT}/get" >/dev/null; then
              exit 0
            fi
            sleep 1
          done
          echo "httpbin did not become ready in time" >&2
          exit 1

      - name: Start httpbin (Docker)
        if: ${{ runner.os == 'Linux' }}
        shell: bash
        run: |
          set -euo pipefail
          PORT=8080
          IMAGE=kennethreitz/httpbin:latest
          docker pull --platform linux/amd64 "$IMAGE"
          docker rm -f shell-download-httpbin 2>/dev/null || true
          docker run -d --name shell-download-httpbin --rm --platform linux/amd64 -p "127.0.0.1:${PORT}:80" "$IMAGE"
          echo "SHELL_DOWNLOAD_HTTPBIN=http://127.0.0.1:${PORT}" >> "$GITHUB_ENV"
          for _ in $(seq 1 60); do
            if curl -sfS "http://127.0.0.1:${PORT}/get" >/dev/null; then
              exit 0
            fi
            sleep .1
          done
          echo "httpbin did not become ready in time" >&2
          docker logs shell-download-httpbin 2>&1 || true
          exit 1

      - name: Run clippy (${{ matrix.feature_combo }})
        shell: bash
        run: cargo clippy ${{ matrix.cargo_args }} -- -D warnings

      - name: Run tests (${{ matrix.feature_combo }})
        shell: bash
        run: cargo test ${{ matrix.cargo_args }}
