import test from 'node:test';
import assert from 'node:assert/strict';
import { createServer } from 'node:net';
import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { ApprovalChannel, should_request_approval } from './approval.ts';
import pager from './device-lab-pager.ts';

test('archived inspection grammar; mutations, composition and unknown tools need approval', () => {
  for (const name of ['read','grep','search','ls','list','find']) assert.equal(should_request_approval(name, {}), false);
  for (const command of ['pwd','git status --short','git diff','ls -la','cat /tmp/test']) assert.equal(should_request_approval('bash', {command}), false);
  for (const command of ['rm x','git push','systemctl restart x','ls; touch x','cat $(touch x)','echo hi > x','python3 script.py','find . -delete','git -c alias.x=!touch x']) assert.equal(should_request_approval('bash', {command}), true);
  for (const name of ['write','edit','apply_patch','delete','deploy','read_and_delete','custom']) assert.equal(should_request_approval(name, {}), true);
});

test('production Pi pager never registers synthetic tool-call approval', async () => {
  const handlers=new Map<string,any>();
  pager({on:(name:string,fn:any)=>handlers.set(name,fn)} as any);
  assert.equal(handlers.has('tool_call'),false);
  // Official native UI bridge has its own protocol; the event pager only reports state.
  assert.equal(handlers.has('session_shutdown'),true);
});

test('archived approval channel waits past the old limit using a controlled clock', async t => {
  const dir=mkdtempSync(join(tmpdir(),'pi-indefinite-'));
  let peer: any;
  let accepted!: () => void;
  const ack=new Promise<void>(r=>accepted=r);
  const server=createServer(s=>{peer=s;s.on('data',()=>{s.write('{"state":"PENDING","approval_id":"long"}\n');accepted();});});
  await new Promise<void>(r=>server.listen(join(dir,'approvals.sock'),r));
  t.mock.timers.enable({apis:['setTimeout']});
  const channel=new ApprovalChannel(5000,join(dir,'approvals.sock'));
  let settled=false;
  const pending=channel.request({test:'wait'}).then(r=>{settled=true;return r;});
  try {
    await ack;
    await new Promise(r=>setImmediate(r));
    await new Promise(r=>setImmediate(r));
    t.mock.timers.tick(4*60*60*1000);
    assert.equal(settled,false);
    peer.end('{"approval_id":"long","state":"APPROVED","decision":"approve"}\n');
    assert.equal(await pending,true);
  } finally {
    channel.close();peer?.destroy();t.mock.timers.reset();
    await new Promise<void>(r=>server.close(()=>r()));rmSync(dir,{recursive:true,force:true});
  }
});
