import { execFileSync } from "node:child_process";
import { readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { setTimeout as pause } from "node:timers/promises";
import { expect } from "e2e";
import { test, WEB } from "./t3.ts";

const direction = process.env.PROOF_DIRECTION ?? "shrink";
let block = process.env.PROOF_BLOCK ?? "";
const setMemory = (state: string) => {
  block = execFileSync("sudo", ["-n", "python3", "-c", `from pathlib import Path
import sys
state, selected = sys.argv[1:]
candidates = [Path(selected)] if selected else sorted(Path('/sys/devices/system/memory').glob('memory[0-9]*/state'), key=lambda p:int(p.parent.name[6:]), reverse=True)
for p in candidates:
 if p.read_text().strip() == state:
  if selected: print(p); break
  continue
 try: p.write_text(state+'\\n')
 except OSError:
  if selected: raise
  continue
 print(p); break
else: raise RuntimeError('No removable memory block found')`, state, block], {encoding:"utf8"}).trim();
};
const report = `import os, subprocess, json, sys\nfrom pathlib import Path\ntotal = int(next(l.split()[1] for l in Path('/proc/meminfo').read_text().splitlines() if l.startswith('MemTotal:'))) * 1024\ngib=1024**3\nexpected={'MemoryHigh':max(total-6*gib,total//2),'MemoryMax':max(total-4*gib,total*3//4)}\nactual=dict(l.split('=',1) for l in subprocess.check_output(['systemctl','--user','show','app-t3code-agents.slice','-p','MemoryHigh','-p','MemoryMax'],text=True).splitlines())\nactual={k:int(v) for k,v in actual.items()}\nprint('Linux VM / real T3 web terminal / '+sys.argv[1].upper())\nprint('Linux-visible RAM: '+str(total)+' bytes')\nprint('app-t3code-agents.slice')\nfor k,v in expected.items(): print(k+': expected '+str(v)+' | actual '+str(actual[k]))\nprint('RESULT: '+('PASS - limits follow live RAM' if actual==expected else 'FAIL - stale startup limits'))\nprint('No server restart during this memory change.')\nprint('Shell cgroup: '+Path('/proc/self/cgroup').read_text().strip())\nPath(sys.argv[1]+'.json').write_text(json.dumps({'expected':expected,'actual':actual}))\n`;

test("Agent slice limits follow real Linux-visible RAM at the next terminal launch", WEB, async ({t3,app,screen,browser}) => {
  if (direction === "grow") block = readFileSync(process.env.PROOF_MEMORY_STATE!, "utf8").trim();
  const project = await t3.project("memory-demo", {"report.py":report});
  const thread = await t3.thread({project,title:"Live memory limits",messages:["Show a short example"],model:"multi-turn"});
  await t3.open(thread);
  await screen.getByRole("button", "Toggle terminal drawer").tap();
  await screen.getByRole("button", /New Terminal/).waitFor();
  const show = async (phase:string) => {
    await screen.getByRole("textbox", "Terminal input").focus();
    await browser.keyboard.type(`PS1='$ '; clear; python3 report.py ${phase}`);
    await browser.keyboard.press("Enter");
    const path=join(project,phase+'.json');
    for(let n=0; !existsSync(path); n++) { if(n>200) throw new Error('Terminal diagnostic did not complete'); await pause(100); }
    await pause(1000);
    await app.screenshot(phase);
    return JSON.parse(readFileSync(path,'utf8'));
  };
  await show("startup");
  try {
    setMemory(direction === "grow" ? "online" : "offline");
    await screen.getByRole("button", /New Terminal/).tap();
    const observed=await show(direction);
    expect(observed.actual).toEqual(observed.expected);
  } finally {
    setMemory("online");
    const total=Number(execFileSync('node',['-p','require("os").totalmem()'],{encoding:'utf8'}).trim());
    const gib=1024**3;
    execFileSync('systemctl',['--user','set-property','--runtime','app-t3code-agents.slice',`MemoryHigh=${Math.max(total-6*gib,Math.floor(total/2))}`,`MemoryMax=${Math.max(total-4*gib,Math.floor(total*.75))}`]);
  }
});
