# Apple client CI — runs on the self-hosted macOS runner (home-mac-mini-1, host mode;
# see scripts/ci/setup-macos-runner.sh). Builds the Rust core into
# PunktfunkCore.xcframework, then builds + tests the Swift package. Network-dependent
# tests (RemoteFirstLightTests) self-skip without PUNKTFUNK_REMOTE_HOST.
#
# A second job (`screenshots`) captures the App Store Connect screenshots of the REAL UI
# (mac window + iOS/iPad/tvOS Simulators, see clients/apple/tools/screenshots.sh) and attaches
# them to the run as a single zip artifact (`punktfunk-appstore-screenshots`). It is isolated
# from the build/test job and best-effort, so a capture gap never reds the core signal.
name: apple

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

jobs:
  # SECURITY: builds/tests PULL-REQUEST code on the host-mode, persistent `macos-arm64` runner shared
  # with the release-signing job (release.yml, which loads the App Store Connect key). Untrusted PR
  # code could persist on it or harvest signing material. Definitive fix is server-side: enable Gitea's
  # "require approval for PRs from outside collaborators/forks", and/or isolate PR CI on ephemeral
  # runners. The `if:` is a fail-open backstop — it skips fork PRs where Gitea reports the fork flag and
  # still runs same-repo PRs (and where the flag is absent), so it never blocks internal PR CI.
  swift:
    runs-on: macos-arm64
    if: >-
      gitea.event_name != 'pull_request' ||
      gitea.event.pull_request.head.repo.fork != true
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@v4

      - name: Rust toolchain (self-healing on a fresh runner)
        run: |
          if ! command -v rustup >/dev/null && [ ! -x "$HOME/.cargo/bin/rustup" ]; then
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
              | sh -s -- -y --no-modify-path --profile minimal
          fi
          RUSTUP="$(command -v rustup || echo "$HOME/.cargo/bin/rustup")"
          dirname "$RUSTUP" >> "$GITHUB_PATH"
          "$RUSTUP" target add aarch64-apple-darwin x86_64-apple-darwin

      # `punktfunk-core` now decodes Opus in-core for the Apple client (surround), pulling
      # `audiopus_sys`, which builds a vendored static libopus via CMake when pkg-config can't find a
      # system Opus — so the xcframework is self-contained (no runtime libopus.dylib on end-user Macs).
      # CMake must be on PATH; install it self-healing on a fresh runner.
      - name: CMake (for the vendored libopus audiopus_sys builds)
        run: |
          # Runner steps run with `bash --noprofile --norc`, so Homebrew's bin dir isn't on PATH —
          # locate brew explicitly, install cmake if missing, and export its bin dir to GITHUB_PATH so
          # the xcframework build step (audiopus_sys → vendored libopus) finds `cmake`.
          for B in /opt/homebrew/bin/brew /usr/local/bin/brew; do [ -x "$B" ] && BREW="$B" && break; done
          if [ -z "$BREW" ]; then echo "::error::Homebrew not found on the runner"; exit 1; fi
          BREW_BIN="$(dirname "$BREW")"; export PATH="$BREW_BIN:$PATH"
          command -v cmake >/dev/null || "$BREW" install cmake
          echo "$BREW_BIN" >> "$GITHUB_PATH"
          # Homebrew's CMake 4 dropped compatibility with the vendored libopus's pre-3.5
          # `cmake_minimum_required`; treat 3.5 as the policy minimum (the cmake crate's child cmake
          # inherits this from the env during the xcframework build).
          echo "CMAKE_POLICY_VERSION_MINIMUM=3.5" >> "$GITHUB_ENV"

      - name: Build PunktfunkCore.xcframework
        run: bash scripts/build-xcframework.sh

      - name: Build (PunktfunkKit + PunktfunkClient app shell)
        working-directory: clients/apple
        run: swift build

      - name: Test (unit + real-codec round trip; remote tests self-skip)
        working-directory: clients/apple
        run: swift test

  # App Store screenshots of the real UI, zipped and attached to the run as a build artifact.
  # Skipped on PRs (cost); runs on main pushes + manual dispatch. Needs the build/test job green
  # first, and is a separate job so a capture hiccup can never red the core signal.
  #
  # Scope = the two REQUIRED iOS sizes (iPhone 6.9" + iPad 13"), captured on the Simulator
  # (`simctl io screenshot`, no Screen Recording grant needed). macOS and tvOS are deliberately
  # NOT in CI: the self-hosted runner is headless (no window-server session), so the mac window
  # capture can't run there; tvOS needs the Tier-3 build-std slice. Generate those two locally on
  # a GUI Mac with `clients/apple/tools/screenshots.sh macos tvos`.
  screenshots:
    needs: swift
    if: gitea.event_name != 'pull_request'
    runs-on: macos-arm64
    timeout-minutes: 75
    steps:
      - uses: actions/checkout@v4

      - name: Rust toolchain + iOS Simulator targets
        run: |
          if ! command -v rustup >/dev/null && [ ! -x "$HOME/.cargo/bin/rustup" ]; then
            curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
              | sh -s -- -y --no-modify-path --profile minimal
          fi
          RUSTUP="$(command -v rustup || echo "$HOME/.cargo/bin/rustup")"
          dirname "$RUSTUP" >> "$GITHUB_PATH"
          "$RUSTUP" target add aarch64-apple-darwin x86_64-apple-darwin \
            aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios

      # See the swift job: audiopus_sys (via the in-core Opus decode) builds vendored libopus with CMake.
      - name: CMake (for the vendored libopus audiopus_sys builds)
        run: |
          # Runner steps run with `bash --noprofile --norc`, so Homebrew's bin dir isn't on PATH —
          # locate brew explicitly, install cmake if missing, and export its bin dir to GITHUB_PATH so
          # the xcframework build step (audiopus_sys → vendored libopus) finds `cmake`.
          for B in /opt/homebrew/bin/brew /usr/local/bin/brew; do [ -x "$B" ] && BREW="$B" && break; done
          if [ -z "$BREW" ]; then echo "::error::Homebrew not found on the runner"; exit 1; fi
          BREW_BIN="$(dirname "$BREW")"; export PATH="$BREW_BIN:$PATH"
          command -v cmake >/dev/null || "$BREW" install cmake
          echo "$BREW_BIN" >> "$GITHUB_PATH"
          # Homebrew's CMake 4 dropped compatibility with the vendored libopus's pre-3.5
          # `cmake_minimum_required`; treat 3.5 as the policy minimum (the cmake crate's child cmake
          # inherits this from the env during the xcframework build).
          echo "CMAKE_POLICY_VERSION_MINIMUM=3.5" >> "$GITHUB_ENV"

      - name: Build PunktfunkCore.xcframework (mac + iOS slices)
        run: BUILD_IOS=1 bash scripts/build-xcframework.sh

      - name: Capture screenshots (iPhone 6.9" + iPad 13"; auto-creates the Simulators)
        working-directory: clients/apple
        env:
          SETTLE: "8" # Simulators settle slower than a local run
        run: |
          # Independent invocations: one platform failing skips it, not the other.
          bash tools/screenshots.sh ios  || echo "::warning::iOS (iPhone 6.9\") screenshots skipped"
          bash tools/screenshots.sh ipad || echo "::warning::iPad 13\" screenshots skipped"
          echo "Produced:"; ls -la screenshots || true

      - name: Upload screenshots (zip artifact)
        if: always()
        # v3, not v4: Gitea's artifact backend identifies as GHES, which @actions/artifact v2+
        # (upload-artifact@v4) refuses. v3 uses the older API Gitea supports; download is still a zip.
        uses: actions/upload-artifact@v3
        with:
          name: punktfunk-appstore-screenshots
          path: clients/apple/screenshots
          if-no-files-found: warn
          retention-days: 30
