// Evidence driver for PR #23610. Run from a checkout dir with node_modules resolvable:
//   node /tmp/ev-23610/out/driver.ts --url http://127.0.0.1:PORT --token <pairing token> --log <server log>
import * as NodeFS from "node:fs";
import * as NodeUtil from "node:util";
import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Schema from "effect/Schema";
import * as Stream from "effect/Stream";
import { Socket } from "effect/socket";
import { RpcClient, RpcSerialization } from "effect/rpc";
import {
  ORCHESTRATION_PROTOCOL_HEADER,
  ORCHESTRATION_PROTOCOL_VERSION,
  WsRpcGroup,
} from "@t3tools/contracts";

const { values } = NodeUtil.parseArgs({
  options: {
    url: { type: "string" },
    token: { type: "string" },
    log: { type: "string" },
    label: { type: "string", default: "?" },
  },
});
const origin = values.url!;
const B = "/tmp/ev-23610";
const SPAWNS = `${B}/spawns.log`;
const PROFILE = `${B}/profile.sh`;
const t0 = Date.now();
const ts = () => `[${new Date().toISOString()} +${((Date.now() - t0) / 1000).toFixed(3)}s]`;
const say = (...parts: unknown[]) => console.log(ts(), ...parts);

const spawnLines = () =>
  NodeFS.existsSync(SPAWNS) ? NodeFS.readFileSync(SPAWNS, "utf8").split("\n").filter(Boolean) : [];
const setProfile = (row: string, body: string) => {
  const content = `echo "PROFILE ${row} $$ $(date +%s.%N)" >> ${SPAWNS}\n${body}\n`;
  NodeFS.writeFileSync(PROFILE, content);
  say(`profile.sh for ${row}:\n${content.replace(/^/gm, "    | ")}`);
};
const logSize = () => (values.log ? NodeFS.statSync(values.log).size : 0);
const logSince = (offset: number) => {
  if (!values.log) return [];
  const fd = NodeFS.openSync(values.log, "r");
  const size = NodeFS.fstatSync(fd).size;
  const buf = Buffer.alloc(Math.max(0, size - offset));
  NodeFS.readSync(fd, buf, 0, buf.length, offset);
  NodeFS.closeSync(fd);
  return buf
    .toString("utf8")
    .split("\n")
    .filter((l) => /login shell|PATH/i.test(l));
};

const tokenResponse = await fetch(`${origin}/oauth/token`, {
  method: "POST",
  body: new URLSearchParams({
    grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
    subject_token: values.token!,
    subject_token_type: "urn:t3:params:oauth:token-type:environment-bootstrap",
    requested_token_type: "urn:ietf:params:oauth:token-type:access_token",
  }),
});
if (!tokenResponse.ok) throw new Error(`auth failed ${tokenResponse.status} ${await tokenResponse.text()}`);
const access = Schema.decodeUnknownSync(Schema.Struct({ access_token: Schema.String }))(
  await tokenResponse.json(),
);
const ticketResponse = await fetch(`${origin}/api/auth/websocket-ticket`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${access.access_token}`,
    [ORCHESTRATION_PROTOCOL_HEADER]: String(ORCHESTRATION_PROTOCOL_VERSION),
  },
});
if (!ticketResponse.ok) throw new Error(`ticket failed ${ticketResponse.status}`);
const ticket = Schema.decodeUnknownSync(Schema.Struct({ ticket: Schema.String }))(
  await ticketResponse.json(),
);
const layerProtocol = RpcClient.layerProtocolSocket().pipe(
  Layer.provide(
    Socket.layerWebSocket(
      `${origin.replace("http:", "ws:")}/ws?orchestrationProtocol=${ORCHESTRATION_PROTOCOL_VERSION}&wsTicket=${encodeURIComponent(ticket.ticket)}`,
    ).pipe(Layer.provide(Socket.layerWebSocketConstructorGlobal)),
  ),
  Layer.provide(RpcSerialization.layerJson),
);

const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;?]*[a-zA-Z]|\x1b\][^\x07]*\x07|\r/g, "");

const program = Effect.gen(function* () {
  const client = yield* RpcClient.make(WsRpcGroup);
  const output = new Map<string, string>();
  yield* client.subscribeTerminalEvents({}).pipe(
    Stream.runForEach((event) =>
      Effect.sync(() => {
        if (event.type === "output") {
          output.set(event.terminalId, (output.get(event.terminalId) ?? "") + event.data);
        }
      }),
    ),
    Effect.forkScoped,
  );

  let terminalCount = 0;
  const terminal = (label: string) =>
    Effect.gen(function* () {
      const terminalId = `ev${++terminalCount}`;
      yield* client["terminal.open"]({
        threadId: "ev-23610-thread",
        terminalId,
        cwd: B,
        cols: 200,
        rows: 50,
      });
      yield* client["terminal.write"]({
        threadId: "ev-23610-thread",
        terminalId,
        data: 'echo "PATH=$PATH"; which -a git claude codex glab; echo "__EV""DONE__"\n',
      });
      for (let i = 0; i < 100; i++) {
        if (stripAnsi(output.get(terminalId) ?? "").includes("\n__EVDONE__")) break;
        yield* Effect.sleep("100 millis");
      }
      const lines = stripAnsi(output.get(terminalId) ?? "")
        .split("\n")
        .filter((l) => l.startsWith("PATH=") || l.startsWith("/"));
      say(`terminal ${label} (${terminalId}):\n${lines.map((l) => `    > ${l}`).join("\n")}`);
      yield* client["terminal.close"]({ threadId: "ev-23610-thread", terminalId }).pipe(Effect.ignore);
      return lines;
    });

  const summarize = (result: any) =>
    [
      ...result.versionControlSystems.map((i: any) => ({ group: "vcs", ...i })),
      ...result.sourceControlProviders.map((i: any) => ({ group: "provider", ...i })),
    ]
      .map(
        (i: any) =>
          `    ${i.group}:${i.kind} status=${i.status} version=${JSON.stringify(i.version ?? null)} exe=${JSON.stringify(i.executable ?? null)}`,
      )
      .join("\n");

  const discover = (label: string) =>
    Effect.gen(function* () {
      const start = Date.now();
      say(`discover ${label}: start`);
      const result = yield* client["server.discoverSourceControl"]({});
      const ms = Date.now() - start;
      say(`discover ${label}: done in ${ms} ms\n${summarize(result)}`);
      return { ms, result };
    });

  const row = (name: string, body: Effect.Effect<void, any, any>) =>
    Effect.gen(function* () {
      console.log(`\n========== ${name} ==========`);
      yield* body;
    });

  // --- R2: page open alone ---
  yield* row(
    "R2 page open (single discovery, profile changed after start)",
    Effect.gen(function* () {
      setProfile("R2", `export PATH=${B}/fakebin-a:$PATH`);
      yield* terminal("R2 before-discovery");
      const before = spawnLines().length;
      yield* discover("R2");
      const added = spawnLines().slice(before);
      say(`R2 spawns.log lines added: ${added.length}\n${added.map((l) => `    + ${l}`).join("\n")}`);
      yield* terminal("R2 after-discovery");
    }),
  );

  // --- R3: slow profile ---
  yield* row(
    "R3 slow profile (trap TERM; sleep 60)",
    Effect.gen(function* () {
      setProfile("R3", `trap '' TERM; sleep 60`);
      const offset = logSize();
      const before = spawnLines().length;
      yield* discover("R3");
      const added = spawnLines().slice(before);
      say(`R3 spawns.log lines added: ${added.length}\n${added.map((l) => `    + ${l}`).join("\n")}`);
      yield* Effect.sleep("300 millis");
      say(`R3 server log lines (login shell / PATH):\n${logSince(offset).map((l) => `    ! ${l}`).join("\n")}`);
      yield* terminal("R3 after-discovery");
    }),
  );

  // --- R4: failing profile ---
  yield* row(
    "R4 failing profile (exit 3)",
    Effect.gen(function* () {
      setProfile("R4", `export PATH=${B}/fakebin-fail:$PATH; exit 3`);
      const offset = logSize();
      const before = spawnLines().length;
      yield* discover("R4");
      const added = spawnLines().slice(before);
      say(`R4 spawns.log lines added: ${added.length}\n${added.map((l) => `    + ${l}`).join("\n")}`);
      say(`R4 server log lines:\n${logSince(offset).map((l) => `    ! ${l}`).join("\n")}`);
      const lines = yield* terminal("R4 after-discovery");
      say(`R4 terminal PATH contains fakebin-fail: ${lines.some((l) => l.includes("fakebin-fail"))}`);
    }),
  );

  // --- R5: reorder ---
  yield* row(
    "R5 reorder (fake git/claude/codex prepended)",
    Effect.gen(function* () {
      setProfile("R5", `export PATH=${B}/fakebin-r:$PATH`);
      const { result } = yield* discover("R5");
      const git = result.versionControlSystems.find((i: any) => i.kind === "git");
      say(`R5 discovery git version: ${JSON.stringify(git?.version ?? null)}`);
      yield* terminal("R5 after-discovery");
    }),
  );

  // --- R6: overlap ---
  yield* row(
    "R6 overlap (3 concurrent discoveries, sleep 2 profile)",
    Effect.gen(function* () {
      setProfile("R6", `sleep 2`);
      const before = spawnLines().length;
      const results = yield* Effect.all(
        [discover("R6#1"), discover("R6#2"), discover("R6#3")],
        { concurrency: "unbounded" },
      );
      const added = spawnLines().slice(before);
      say(
        `R6 timings ms: ${results.map((r) => r.ms).join(", ")}; spawns.log lines added: ${added.length}\n${added.map((l) => `    + ${l}`).join("\n")}`,
      );

      const before2 = spawnLines().length;
      const victim = yield* Effect.forkChild(discover("R6-cancel#A"));
      const survivor = yield* Effect.forkChild(discover("R6-cancel#B"));
      yield* Effect.sleep("500 millis");
      yield* Fiber.interrupt(victim);
      say("R6-cancel#A interrupted at ~500 ms");
      const s = yield* Fiber.join(survivor);
      const added2 = spawnLines().slice(before2);
      say(`R6-cancel survivor finished in ${s.ms} ms; spawns.log lines added: ${added2.length}`);
    }),
  );
});

await Effect.runPromise(program.pipe(Effect.scoped, Effect.provide(layerProtocol)));
say(`driver (${values.label}) finished`);
process.exit(0);
