#!/usr/bin/env bash
# gate0's remote dispatch seam: the decision file, not the exit code, says whether
# the check ran on a box — the dispatcher's exit code IS the check's exit code.
set -uo pipefail

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)"
GATES="$REPO/modules/harness/lib/gates.sh"
[[ -x "$GATES" ]] || { echo "FAIL: gates.sh not executable at $GATES" >&2; exit 1; }

root=$(mktemp -d "${TMPDIR:-/tmp}/gate0-dispatch-XXXXXX")
trap 'rm -rf "$root"' EXIT
pass=0
fail=0

check() {
  local name=$1 expected=$2 actual=$3
  if [[ "$expected" == "$actual" ]]; then
    pass=$((pass + 1))
    printf '  ok   %s\n' "$name"
  else
    fail=$((fail + 1))
    printf '  FAIL %s\n     expected: %s\n     actual:   %s\n' "$name" "$expected" "$actual" >&2
  fi
}

mkdir -p "$root/bin"
real_node=$(command -v node)
# Stands in for gate-dispatch.mjs only when gates.sh dispatches a check; every
# other node call in the gate must still reach the real interpreter.
cat > "$root/bin/node" <<STUB
#!/usr/bin/env bash
decision=""
for arg in "\$@"; do
  [[ -n "\${want:-}" ]] && { decision="\$arg"; want=""; }
  [[ "\$arg" == "--decision" ]] && want=1
done
if [[ -z "\$decision" ]]; then exec "$real_node" "\$@"; fi
printf 'dispatcher-ran\n'
printf '%s\n' "\$*" > "$root/dispatch-argv"
[[ -n "\${STUB_DECISION:-}" ]] && printf '%s\n' "\$STUB_DECISION" > "\$decision"
exit "\${STUB_RC:-0}"
STUB
cat > "$root/bin/npm" <<'STUB'
#!/usr/bin/env bash
printf 'local-npm %s\n' "$*"
printf 'checkenv VITEST_MAX_FORKS=%s fail_if_no_match=%s\n' \
  "${VITEST_MAX_FORKS:-unset}" "${npm_config_fail_if_no_match:-unset}"
exit "${LOCAL_RC:-0}"
STUB
chmod +x "$root/bin/node" "$root/bin/npm"

: > "$root/dispatch.mjs"

mkrepo() {
  local d
  d=$(mktemp -d "$root/repo-XXXXXX")
  git -C "$d" init -q
  git -C "$d" config user.email t@t.t
  git -C "$d" config user.name t
  git -C "$d" config commit.gpgsign false
  mkdir -p "$d/.git/hooks-empty"
  git -C "$d" config core.hooksPath "$d/.git/hooks-empty"
  printf '%s\n' '{"scripts": {"test": "true"}}' > "$d/package.json"
  git -C "$d" add package.json
  git -C "$d" commit -q -m seed
  printf '%s' "$d"
}

# An uncreatable state dir makes the whole-gate dispatch layer return 250 without
# contacting a box, leaving the per-check seam under test as the only dispatcher.
run_gate() {
  local repo=$1
  PATH="$root/bin:$PATH" \
  GATE0_REMOTE_STATE=/dev/null/no-state \
  GATE0_DISPATCH="${GATE0_DISPATCH:-$root/dispatch.mjs}" \
  GATE0_REMOTE="${GATE0_REMOTE:-1}" \
  STUB_DECISION="${STUB_DECISION:-}" \
  STUB_RC="${STUB_RC:-0}" \
  LOCAL_RC="${LOCAL_RC:-0}" \
  VITEST_MAX_FORKS=3 \
    "$GATES" gate0 strict "$repo" "$repo" dispatch 2>&1
  printf 'GATERC=%s\n' "$?"
}

gaterc() { sed -n 's/^GATERC=//p' <<< "$1"; }
count() { grep -cF -e "$2" <<< "$1"; }

r=$(mkrepo)

# A remote verdict returns the dispatcher's exit code as the check's own.
out=$(STUB_DECISION="remote " STUB_RC=7 run_gate "$r")
check "remote verdict fails the gate on a remote red" "1" "$(gaterc "$out")"
check "remote verdict reports the remote rc" "1" "$(count "$out" "rc=7")"
check "remote verdict skips the local run" "0" "$(count "$out" "local-npm")"

out=$(STUB_DECISION="remote " STUB_RC=0 run_gate "$r")
check "remote green passes the gate" "0" "$(gaterc "$out")"
check "remote green skips the local run" "0" "$(count "$out" "local-npm")"

# The remote run must be the same check, not a laxer one.
argv=$(cat "$root/dispatch-argv")
check "dispatch forwards worker limits" "1" "$(count "$argv" "--env VITEST_MAX_FORKS=3")"
check "dispatch forwards strictness" "1" "$(count "$argv" "--env npm_config_fail_if_no_match=true")"
check "dispatch forwards the pnpm filter guard" "1" "$(count "$argv" "--env PNPM_CONFIG_FAIL_IF_NO_MATCH=true")"
check "dispatch names the check" "1" "$(count "$argv" "--check test")"
check "dispatch passes the check command" "1" "$(count "$argv" "-- $root/bin/npm run test")"

# A declined verdict runs the check here, with its strictness env intact.
# gate0 only echoes a check's captured output when the check goes red, so the
# assertions on that output ride a deliberately-red local run.
out=$(STUB_DECISION="local unreachable-or-full" LOCAL_RC=4 run_gate "$r")
check "declined verdict runs locally" "1" "$(count "$out" "local-npm run test")"
check "declined verdict names the reason" "1" "$(count "$out" "remote dispatch declined (unreachable-or-full)")"
check "declined verdict keeps strictness env" "1" \
  "$(count "$out" "checkenv VITEST_MAX_FORKS=3 fail_if_no_match=true")"
check "declined verdict propagates a local red" "1" "$(gaterc "$out")"
check "declined verdict reports the local rc" "1" "$(count "$out" "rc=4")"

out=$(STUB_DECISION="local disabled" run_gate "$r")
check "declined verdict passes on a local green" "0" "$(gaterc "$out")"

# A fleet that never answered fails the gate closed instead of moving the heavy
# check onto the workstation.
out=$(STUB_DECISION="blocked dispatch-timeout:debian2,debian1" STUB_RC=1 LOCAL_RC=0 run_gate "$r")
check "blocked verdict fails closed" "1" "$(gaterc "$out")"
check "blocked verdict is infra-classed" "1" "$(count "$out" "FAILCLASS=infra")"
check "blocked verdict names the hosts" "1" "$(count "$out" "dispatch-timeout:debian2,debian1")"
check "blocked verdict does not run locally" "0" "$(count "$out" "local-npm")"

# No decision at all is an infra failure, never a pass.
out=$(STUB_DECISION="" run_gate "$r")
check "missing decision fails closed" "1" "$(gaterc "$out")"
check "missing decision is infra-classed" "1" "$(count "$out" "FAILCLASS=infra")"
check "missing decision does not run locally" "0" "$(count "$out" "local-npm")"

# The escape hatch runs locally without consulting the dispatcher.
out=$(GATE0_REMOTE=0 STUB_DECISION="remote " LOCAL_RC=4 run_gate "$r")
check "GATE0_REMOTE=0 bypasses dispatch" "0" "$(count "$out" "dispatcher-ran")"
check "GATE0_REMOTE=0 runs locally" "1" "$(count "$out" "local-npm run test")"

# An undeployed dispatcher is the exact shape of "arming did not work", so it says
# so rather than looking identical to a working offload.
out=$(GATE0_DISPATCH="$root/absent.mjs" LOCAL_RC=4 run_gate "$r")
check "absent dispatcher is announced" "1" "$(count "$out" "remote dispatch unavailable")"
check "absent dispatcher runs locally" "1" "$(count "$out" "local-npm run test")"
check "absent dispatcher propagates the local rc" "1" "$(gaterc "$out")"

out=$(GATE0_DISPATCH="$root/absent.mjs" run_gate "$r")
check "absent dispatcher passes on a local green" "0" "$(gaterc "$out")"

printf 'gate0-remote-dispatch: pass=%d fail=%d\n' "$pass" "$fail"
(( fail == 0 ))
