#!/bin/sh
set -eu
# Run from a dependency-installed T3 Code checkout at the revision being checked.
root=$(pwd -P)
scratch=${REPRO_SCRATCH:-${TMPDIR:-/tmp}}
work=$(mktemp -d "$scratch/fx-probe-verify.XXXXXX")
mkdir -p "$work/fake-home" "$work/tmp" "$work/t3"
export HOME="$work/fake-home" TMPDIR="$work/tmp" T3CODE_HOME="$work/t3"
printf 'Runtime: production checkFxProviderStatus, real NodeServices, synthetic fx fixture\n'
cat > "$work/fx-fixture" <<'JS'
#!/usr/bin/env node
const fs = require('node:fs');
const args = process.argv.slice(2);
const isStatus = args[0] === 'status';
const shouldHang = process.env.FX_CASE !== 'healthy' && isStatus;
fs.appendFileSync(process.env.FX_EVENTS, JSON.stringify({pid:process.pid,args,event:'spawn'})+'\n');
if (shouldHang) {
  if (process.env.FX_CASE === 'ignore-term') {
    process.on('SIGTERM', () => fs.appendFileSync(process.env.FX_EVENTS, JSON.stringify({pid:process.pid,event:'SIGTERM'})+'\n'));
  }
  setInterval(() => {}, 1000);
} else {
  console.log(args[0] === '--version' ? 'fx 0.0.13' : isStatus ? JSON.stringify({auth:'api-key',model:'test-model'}) : JSON.stringify({ids:['test-model']}));
}
JS
chmod +x "$work/fx-fixture"
cat > "$work/run.mjs" <<'JS'
import fs from 'node:fs';
import { createRequire } from 'node:module';
import { pathToFileURL } from 'node:url';
const root = process.env.REPRO_ROOT;
const req = createRequire(`${root}/packages/provider-fx/package.json`);
const Effect = await import(req.resolve('effect/Effect'));
const Schema = await import(req.resolve('effect/Schema'));
const NodeServices = await import(req.resolve('@effect/platform-node/NodeServices'));
const { FxSettings } = await import(pathToFileURL(`${root}/packages/provider-fx/src/settings.ts`));
const { checkFxProviderStatus } = await import(pathToFileURL(`${root}/packages/provider-fx/src/server/status.ts`));
const settings = Schema.decodeSync(FxSettings)({ enabled:true,binaryPath:process.env.FX_BINARY });
const started = performance.now();
const snapshot = await Effect.runPromise(checkFxProviderStatus(settings,process.env).pipe(Effect.provide(NodeServices.layer)));
fs.writeFileSync(process.env.FX_RESULT,JSON.stringify({elapsedMs:Math.round(performance.now()-started),status:snapshot.status,auth:snapshot.auth,message:snapshot.message,models:snapshot.models.map(m=>m.slug)}));
JS
cat > "$work/observe.mjs" <<'JS'
import { spawn } from 'node:child_process';
import fs from 'node:fs';
import assert from 'node:assert/strict';
const work = process.env.REPRO_WORK;
const alive = pid => { try { process.kill(pid,0); return true; } catch(e) { if(e.code === 'ESRCH') return false; throw e; } };
const pause = ms => new Promise(r=>setTimeout(r,ms));
const owned = new Set();
const results = [];
try {
  for (const mode of ['healthy','normal-term','ignore-term']) {
    const events = `${work}/${mode}.events`;
    const result = `${work}/${mode}.json`;
    const child = spawn(process.execPath,[`${work}/run.mjs`],{env:{...process.env,FX_CASE:mode,FX_EVENTS:events,FX_RESULT:result,FX_BINARY:`${work}/fx-fixture`},stdio:['ignore','pipe','pipe']});
    owned.add(child.pid);
    let stderr=''; child.stderr.on('data',b=>stderr+=b);
    const started=performance.now();
    const exit = new Promise(resolve=>child.on('exit',(code,signal)=>resolve({code,signal})));
    const outcome = await Promise.race([exit,pause(mode==='ignore-term'?22000:15000).then(()=>null)]);
    const records=fs.existsSync(events)?fs.readFileSync(events,'utf8').trim().split('\n').filter(Boolean).map(l=>JSON.parse(l)):[];
    for (const record of records) owned.add(record.pid);
    const hungPid=records.find(r=>r.args?.[0]==='status')?.pid;
    const entry={case:mode,observedMs:Math.round(performance.now()-started),returned:fs.existsSync(result),statusChildAlive:hungPid!==undefined&&alive(hungPid),signals:records.filter(r=>r.event==='SIGTERM').length,...(fs.existsSync(result)?{result:JSON.parse(fs.readFileSync(result,'utf8'))}:{})};
    console.log(JSON.stringify(entry));
    if(stderr) console.log(`stderr: ${stderr}`);
    if(mode==='ignore-term') {
      if (entry.returned) { console.log('Returned without external intervention.'); continue; }
      process.kill(hungPid,'SIGKILL');
      const released=await Promise.race([exit,pause(5000).then(()=>null)]);
      assert.deepEqual(released,{code:0,signal:null});
      console.log('After killing only the recorded stuck CLI PID: '+fs.readFileSync(result,'utf8'));
    } else {
      assert.deepEqual(outcome,{code:0,signal:null}); assert.equal(entry.returned,true); assert.equal(entry.statusChildAlive,false);
      assert.equal(entry.result.status,mode==='healthy'?'ready':'warning');
      if(mode==='normal-term') assert.ok(entry.result.elapsedMs>=9500&&entry.result.elapsedMs<15000);
    }
    results.push(entry);
  }
  console.log('Observation complete; compare ignore-term return state and live-process state above.');
} finally {
  for(const pid of owned) if(alive(pid)) { try {process.kill(pid,'SIGKILL');} catch(e) {if(e.code!=='ESRCH')throw e;} }
}
JS
REPRO_ROOT="$root" REPRO_WORK="$work" node "$work/observe.mjs"
