// Scratch repro for pingdotgg/t3code#18165: does the server-browser host outlive its last tab?
// Run from <worktree>/apps/server: node /tmp/.../repro-idle-host.ts <worktree> <chrome> <waitSeconds>
import { execFileSync } from "node:child_process";
import * as NodeFS from "node:fs";
import * as NodePath from "node:path";

const [worktree, chrome, waitArg] = process.argv.slice(2);
const waitSeconds = Number(waitArg ?? "90");
const { ServerBrowserContexts } = await import(
  NodePath.join(worktree!, "apps/server/src/preview/ServerBrowserContexts.ts")
);

const profilesDir = NodeFS.mkdtempSync("/tmp/issue-lead-18165-r2/repro/profiles-");
const descendants = () => {
  const out = execFileSync("ps", ["-eo", "pid,ppid,etimes,time,args"], { encoding: "utf8" });
  const rows = out
    .trim()
    .split("\n")
    .slice(1)
    .map((line) => {
      const [pid, ppid, etimes, time, ...args] = line.trim().split(/\s+/);
      return { pid: Number(pid), ppid: Number(ppid), etimes, time, args: args.join(" ") };
    });
  const ours = new Set([process.pid]);
  let grew = true;
  while (grew) {
    grew = false;
    for (const row of rows)
      if (!ours.has(row.pid) && ours.has(row.ppid)) {
        ours.add(row.pid);
        grew = true;
      }
  }
  return rows.filter((row) => row.pid !== process.pid && ours.has(row.pid) && row.args.includes("chrome"));
};
const show = (label: string) => {
  const rows = descendants();
  console.log(`[${new Date().toISOString()}] ${label}: ${rows.length} chrome process(es)`);
  for (const row of rows)
    console.log(`  pid=${row.pid} up=${row.etimes}s cpu=${row.time} ${row.args.slice(0, 160)}`);
};

const pool = new ServerBrowserContexts({ profilesDir, executable: async () => chrome!, env: process.env });

const context = await pool.contextFor("default");
const page = await context.newPage();
await page.setContent("<h1>preview</h1>");
show("default-profile tab open");
await page.close();
show("tab closed");

const agent = await pool.contextFor("default", "thread:tab-agent");
const agentPage = await agent.newPage();
show("isolated agent tab open");
await agentPage.close();
await agent.close();
show("agent tab and its context closed");

await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));
show(`${waitSeconds}s after the last tab closed`);
await pool.close();
show("pool.close() (server shutdown)");
