import fs from 'node:fs';
import { randomUUID } from 'node:crypto';
import * as NodeWS from '@effect/platform-node/NodeWS';
import { WsRpcGroup, ORCHESTRATION_PROTOCOL_VERSION, ORCHESTRATION_PROTOCOL_HEADER } from '@t3tools/contracts';
import * as Effect from 'effect/Effect';
import * as Layer from 'effect/Layer';
import * as Stream from 'effect/Stream';
import { RpcClient, RpcSerialization } from 'effect/rpc';
import { Socket } from 'effect/socket';
const [origin,tokenFile,gateway,sha,out]=process.argv.slice(2);
const token=fs.readFileSync(tokenFile,'utf8').trim().split('\n').at(-1)!;
const started=Date.now();
const rows:any[]=[];
const log=(event:string,data:unknown)=>{const row={seconds:+((Date.now()-started)/1000).toFixed(1),event,data};rows.push(row);fs.writeFileSync(out,JSON.stringify(rows,null,2));console.log(JSON.stringify(row));};
const req=async(path:string,body?:unknown)=>{const response=await fetch(origin+path,{method:body===undefined?'GET':'POST',headers:{authorization:`Bearer ${token}`,'content-type':'application/json',[ORCHESTRATION_PROTOCOL_HEADER]:String(ORCHESTRATION_PROTOCOL_VERSION)},...(body===undefined?{}:{body:JSON.stringify(body)})});if(!response.ok)throw new Error(`${path} HTTP ${response.status}: ${await response.text()}`);return response.json();};
Effect.runPromise(Effect.scoped(Effect.gen(function*(){
 log('environment',{commit:sha,surface:'Real T3 server, WebSocket RPC; local capped gateway fixture; real agent-device 0.21.36; wall clock',maxTtlMs:300000,maxLeaseMinutes:60});
 const ticket=yield* Effect.promise(()=>req('/api/auth/websocket-ticket',{}));
 const protocol=yield* Layer.build(RpcClient.layerProtocolSocket().pipe(Layer.provide(Socket.layerWebSocket(`${origin.replace('http','ws')}/ws?orchestrationProtocol=${ORCHESTRATION_PROTOCOL_VERSION}&wsTicket=${encodeURIComponent(ticket.ticket)}`)),Layer.provide(RpcSerialization.layerJson),Layer.provide(NodeWS.layerWebSocketConstructor)));
 const client=yield* RpcClient.make(WsRpcGroup).pipe(Effect.provideContext(protocol));
 const existing=yield* Effect.promise(()=>req('/api/orchestration/shell'));
 const projectId=existing.projects?.[0]?.id??randomUUID(),threadId=randomUUID();
 if(!existing.projects?.length)yield* Effect.promise(()=>req('/api/projects/mutate',{type:'project.create',commandId:randomUUID(),projectId,title:'Lease renewal proof',workspaceRoot:process.cwd()}));
 yield* client['orchestration.launchThread']({commandId:randomUUID(),threadId,projectId,title:'Watched device',modelSelection:{instanceId:'codex',model:'gpt-5.4'},runtimeMode:'full-access',interactionMode:'default',workspaceStrategy:{type:'root'}} as any);
 const list=()=>client['device.list']({});
 const brief=(state:any)=>({devices:state.devices.filter((d:any)=>d.hostId==='proof').map((d:any)=>({id:d.id,name:d.name,booted:d.booted})),sessions:state.sessions.filter((s:any)=>s.hostId==='proof').map((s:any)=>({deviceId:s.deviceId}))});
 for(const old of (yield* list()).sessions.filter(s=>s.hostId==='proof'))yield* client['device.close']({...old,shutdown:true});
 log('initial listing',brief(yield* list()));
 const session=yield* client['device.open']({threadId,hostId:'proof',deviceId:'simlock:ios:iPhone 17 Pro',platform:'ios'} as any);
 log('device.open',{deviceId:session.deviceId});
 yield* client['subscribeDeviceState']({}).pipe(Stream.runForEach(()=>Effect.void),Effect.forkScoped);
 log('watch subscribed',brief(yield* list()));
 for(let i=1;i<=13;i++){
  yield* Effect.sleep('30 seconds');
  log('device.list',brief(yield* list()));
  log('gateway transcript',yield* Effect.promise(async()=>await(await fetch(gateway+'/events')).json()));
 }
 log('final outcome',brief(yield* list()));
 yield* client['device.close']({threadId,hostId:'proof',deviceId:'lease-proof',shutdown:true} as any);
 log('closed',brief(yield* list()));
}))).catch(e=>{console.error(String(e));process.exitCode=1;});
