#!/usr/bin/env bash
# check-ios.sh — iOS compile-validation ladder for choreo-gui (the only crate
# that ships to iOS). Runs on ANY host; each stage is independent and the
# deepest stage reached is the report. Exit is non-zero ONLY when stage 1
# (the check) fails — deeper-stage failures are findings, not gate failures.
#
# Stages:
#   0. environment   — rustup iOS targets installed; shim prerequisites (zig
#                      on non-Mac hosts; xcrun detection selects the native
#                      path instead).
#   1. check         — `cargo check -p choreo-gui --target aarch64-apple-ios`
#                      (+ the -sim target): the whole Blitz/wgpu/winit tree
#                      type-checks for iOS. THE gate; everything below is
#                      extra credit.
#   2. codegen       — `cargo rustc --crate-type staticlib`: a self-contained
#                      real .a (the link input Xcode/ld64 consumes — ld64 does
#                      NOT find `.rlib` for -l<name>; see build-ios.sh). The
#                      archive is created internally by rustc, so this needs no
#                      Apple linker and runs on any host; the cdylib (which
#                      would) is deliberately NOT built.
#   3. artifacts     — the link input staged by scripts/build-ios.sh exists
#                      and is sane (self-contained libchoreo_gui.a; since
#                      step 5 of the embedded refactor it also embeds the
#                      whole choreo-daemon tree for the iOS in-process daemon).
#
# WHY THE SHIMS (non-Mac hosts; the full rationale lives in build-ios.sh):
#   - ~/.cargo/config.toml [build] rustflags and the workspace's profile
#     rustflags both carry `-C target-cpu=native` (x86 host CPU). Profile
#     rustflags are NOT suppressible via RUSTFLAGS env (see build-android.sh's
#     header), so a RUSTC wrapper strips the flag for Apple targets.
#   - Apple target: cc-rs's iOS C target args are rewritten to zig's macOS
#     target because zig bundles macOS darwin libc headers but not iOS ones
#     (compile-only difference — the final link always happens on a Mac).
#   - HOST compiles: the iOS-gated choreo-daemon dependency brings build
#     scripts that compile C for the HOST (headless_chrome ->
#     auto_generate_cdp -> ureq/rustls -> ring); the shim maps those to zig's
#     x86_64-linux-gnu instead (see build-ios.sh's cc-shim comment).
#
# KNOWN BASELINE FINDING (recorded 2026-09, toolchain nightly-1.100): ring
# 0.17.14's aarch64-apple darwin module const-asserts that pmull is statically
# available, but current rustc's aarch64-apple-ios baseline cfg no longer
# lists it (aes,neon,pmuv3,sha2). This is a real upstream/lockfile issue that
# will also fire on a Mac — the fix is a `ring` upgrade, not an env tweak.
# If stage 1 fails with that E0080 assert, surface it verbatim.
set -uo pipefail

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"

status=0           # set to 1 only by stage-1 failure
reached=0          # deepest successful stage

log()    { printf '==> %s\n' "$*"; }
pass()   { printf '    PASS: %s\n' "$*"; }
warn()   { printf '    WARN: %s\n' "$*"; }
stage()  { printf '\n── stage %d: %s ─\n' "$1" "$2"; }
bail()   { printf '    FAIL: %s\n' "$*" >&2; }

# ── Stage 0: environment ────────────────────────────────────────────────────
stage 0 "environment"
for target in aarch64-apple-ios aarch64-apple-ios-sim; do
    if rustup target list --installed 2>/dev/null | grep -qx "$target"; then
        pass "rustup target $target installed"
    else
        bail "rustup target $target missing — rustup target add $target"
        status=1
    fi
done

if command -v xcrun >/dev/null 2>&1; then
    pass "Xcode detected — native Apple toolchain path (shims not installed)"
    SHIM_ENV=()
else
    if command -v zig >/dev/null 2>&1; then
        pass "no Xcode; zig $(zig version 2>/dev/null) present — shim path active"
    else
        bail "no Xcode and no zig — install zig (pacman -S zig) for the shim path"
        status=1
    fi
    SHIM_ENV=shims
fi

# Shared shim setup with scripts/build-ios.sh (same wrappers, same caveats).
setup_shims() {
    SHIM_DIR="$REPO_ROOT/target/ios-shims"

# Shared cc/cxx shim generator (see the lib for the triple-translation rationale).
    source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib/ios-cc-shims.sh"

    mkdir -p "$SHIM_DIR"
    RUSTC_REAL="$(rustc --print sysroot)/bin/rustc"

    cat > "$SHIM_DIR/rustc" <<EOF
#!/bin/bash
# Generated by scripts/check-ios.sh — do not edit (see build-ios.sh).
real="$RUSTC_REAL"
has_target=0
for a in "\$@"; do case "\$a" in *apple-ios*) has_target=1 ;; esac; done
if [ \$has_target = 0 ]; then exec "\$real" "\$@"; fi
args=()
for a in "\$@"; do
  if [ "\$a" = "target-cpu=native" ]; then
    if [ "\${#args[@]}" -gt 0 ] && [ "\${args[\${#args[@]}-1]}" = "-C" ]; then
      unset 'args[\${#args[@]}-1]'
    fi
    continue
  fi
  args+=("\$a")
done
exec "\$real" "\${args[@]+"\${args[@]}"}"
EOF

    # The generator lives in scripts/lib/ios-cc-shims.sh (shared with
    # build-ios.sh so the two cannot drift again; the second argument is
    # stamped into the generated header so a stale shim shows where its
    # current generator lives). The generated files are byte-identical to
    # the pre-refactor heredoc output.
    write_ios_cc_shims "$SHIM_DIR" "check-ios.sh"
    chmod +x "$SHIM_DIR/rustc"

    export RUSTC="$SHIM_DIR/rustc"
    # Bare `cc`/`c++` from PATH must also hit the shim (see build-ios.sh).
    export PATH="$SHIM_DIR:$PATH"
    unset RUSTFLAGS 2>/dev/null || true
    # cc shims + fake SDKROOT are for the NO-MAC path only (see build-ios.sh):
    # on a Mac the native clang + real iOS SDK are correct, and exporting the
    # shim over them breaks cc-rs ("exec: zig: not found").
    if command -v xcrun >/dev/null 2>&1; then
        log "using the native Apple C toolchain (no cc shims exported)"
    else
        FAKE_SDK="$REPO_ROOT/target/ios-fake-sdk"
        mkdir -p "$FAKE_SDK/iPhoneOS.platform"
        export CC="$SHIM_DIR/cc" CXX="$SHIM_DIR/cxx" AR="zig ar"
        export SDKROOT="$FAKE_SDK"
    fi
}

# ── Stage 1: check (THE gate) ───────────────────────────────────────────────
stage 1 "cargo check — aarch64-apple-ios (+ sim)"
for target in aarch64-apple-ios aarch64-apple-ios-sim; do
    if cargo check -p choreo-gui --lib --target "$target" 2>&1 | tee /tmp/check-ios-$target.log | grep -q "^error"; then
        bail "cargo check failed for $target — see /tmp/check-ios-$target.log"
        # Surface the known ring baseline failure verbatim so the reader
        # doesn't have to open the log to recognize it.
        grep -m1 "MIN_STATIC_FEATURES" /tmp/check-ios-$target.log \
            && warn "known ring 0.17.14 baseline issue — upgrade ring (see header)"
        status=1
    else
        pass "cargo check $target"
        reached=1
    fi
done

# ── Stage 2: codegen (rlib) ─────────────────────────────────────────────────
stage 2 "staticlib codegen — cargo rustc --crate-type staticlib"
if [ "$reached" -ge 1 ]; then
    if cargo rustc -p choreo-gui --lib --crate-type staticlib --target aarch64-apple-ios 2>&1 \
        | tee /tmp/check-ios-codegen.log | grep -q "^error"; then
        bail "staticlib codegen failed — see /tmp/check-ios-codegen.log (unexpected: archive creation needs no Apple linker)"
    else
        alib="target/aarch64-apple-ios/debug/libchoreo_gui.a"
        if [ -e "$alib" ]; then
            pass "staticlib produced: $alib ($(du -h "$alib" | cut -f1), $(file -b "$alib" | cut -d, -f1))"
            reached=2
        else
            bail "cargo rustc succeeded but $alib missing"
        fi
    fi
else
    warn "skipped (stage 1 failed)"
fi

# ── Stage 3: staged artifacts (from build-ios.sh) ───────────────────────────
stage 3 "staged link inputs (scripts/build-ios.sh layout)"
if [ "$reached" -ge 2 ]; then
    stage_dir="target/ios/iphoneos/debug"
    if [ -e "$stage_dir/libchoreo_gui.a" ]; then
        pass "$stage_dir/libchoreo_gui.a (self-contained: std + ring + secp256k1 + the choreo-daemon tree embedded)"
        reached=3
    else
        warn "$stage_dir not populated — run scripts/build-ios.sh to stage link inputs"
    fi
else
    warn "skipped (earlier stage failed)"
fi

# ── Report ──────────────────────────────────────────────────────────────────
printf '\n== summary: reached stage %d/3, status %s ==\n' "$reached" \
    "$([ "$status" = 0 ] && echo OK || echo FAILED)"
if [ "$status" = 0 ] && [ "$reached" -ge 2 ]; then
    log "everything short of Apple's linker validates on this host."
    log "next: run scripts/build-ios.sh on a Mac (phase 0b) for the final link + boot."
fi
exit "$status"
