name: CI

on:
  push:
    branches: [main]
  pull_request:

env:
  CARGO_TERM_COLOR: always

jobs:
  lint:
    name: Lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy

      - name: Cache cargo registry & build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: lint-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: lint-cargo-

      - name: Check formatting
        run: cargo fmt --check

      - name: Clippy
        run: cargo clippy -- -D warnings
        env:
          RUSTFLAGS: -Dwarnings

      - name: Doc lints
        run: cargo doc --all-features --no-deps
        env:
          RUSTDOCFLAGS: -Dwarnings

  test:
    name: Tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry & build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: test-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: test-cargo-

      - name: Run tests
        run: cargo test

  build:
    name: Build (${{ matrix.name }})
    runs-on: ${{ matrix.runner }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Linux x86_64 (musl)
            runner: ubuntu-latest
            target: x86_64-unknown-linux-musl
          - name: Linux aarch64 (musl)
            runner: ubuntu-24.04-arm
            target: aarch64-unknown-linux-musl
          - name: macOS aarch64
            runner: macos-latest
            target: aarch64-apple-darwin
          - name: Windows x86_64
            runner: windows-latest
            target: x86_64-pc-windows-msvc
            # Statically link the MSVC runtime so the resulting .exe runs on
            # a clean Windows install without VC++ Redistributable.
            rustflags: -C target-feature=+crt-static
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install musl-tools (Linux only)
        if: contains(matrix.target, 'musl')
        run: sudo apt-get update && sudo apt-get install -y musl-tools

      - name: Cache cargo registry & build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ matrix.target }}-cargo-

      - name: Build
        run: cargo build --release --target ${{ matrix.target }}
        env:
          RUSTFLAGS: ${{ matrix.rustflags }}

  build-web:
    name: Build (Web wasm)
    # Catch wasm-only breakage at PR time, not at deploy time. Native and
    # wasm code paths are gated by `cfg(target_arch = "wasm32")`, so a
    # missing field on a struct used by `wasm_app.rs` compiles fine on
    # every native target and only blows up here. (See InputContext +
    # DrawOutput projection in `crate::input` for why most platform-side
    # rect plumbing is now centralized.)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: wasm32-unknown-unknown

      - name: Cache cargo registry & build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: wasm32-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: wasm32-cargo-

      # `cargo check` is enough — the deploy-web workflow does the full
      # trunk pipeline; here we just want the typecheck to fail fast.
      - name: Check wasm build
        run: cargo check --target wasm32-unknown-unknown --release
