'use strict';
// Owned loopback fixture: QScout does not execute or manage these TLS policy transitions.
const tls=require('tls'),fs=require('fs'),crypto=require('crypto'),cp=require('child_process');
const path=require('path');
const root='/workspace/artifacts/ops/qscout-client-investor-proof-20260930/lab/tls';
const key=fs.readFileSync(path.join(root,'private/key.pem'));
const cert=fs.readFileSync(path.join(root,'private/cert.pem'));
const sha=x=>crypto.createHash('sha256').update(x).digest('hex');
const now=()=>new Date().toISOString();
const delay=ms=>new Promise(r=>setTimeout(r,ms));
const record={started_utc:now(),node:process.version,embedded_openssl:process.versions.openssl,system_openssl:cp.execFileSync('/usr/bin/openssl',['version'],{encoding:'utf8'}).trim(),script_sha256:sha(fs.readFileSync(__filename)),certificate_sha256:sha(cert),phases:[]};
async function phase(name,serverGroup,clientGroup,expectSuccess){
  const entry={name,server_group_policy:serverGroup,client_group_policy:clientGroup,expected_success:expectSuccess,started_utc:now(),handshake_errors:[],connections:[]};
  let server;
  try{
    server=tls.createServer({key,cert,minVersion:'TLSv1.3',maxVersion:'TLSv1.3',ecdhCurve:serverGroup,enableTrace:process.env.TRACE_TLS==='1'},socket=>{
      const info={protocol:socket.getProtocol(),cipher:socket.getCipher(),ephemeral:socket.getEphemeralKeyInfo?.()??null,authorized:socket.authorized};
      entry.connections.push(info);
      socket.once('data',data=>{entry.server_request=data.toString();socket.end('HTTP/1.1 200 OK\r\nContent-Length: 12\r\nConnection: close\r\n\r\nowned-lab-ok');});
    });
    server.on('tlsClientError',e=>entry.handshake_errors.push({side:'server',code:e.code||null,message:e.message}));
    await new Promise((resolve,reject)=>{server.once('error',reject);server.listen(0,'127.0.0.1',resolve);});
    entry.listening_at=now();entry.port=server.address().port;
    await new Promise(resolve=>{
      let done=false;const finish=()=>{if(!done){done=true;resolve();}};
      let client;
      try{client=tls.connect({host:'127.0.0.1',port:entry.port,servername:'localhost',rejectUnauthorized:false,minVersion:'TLSv1.3',maxVersion:'TLSv1.3',ecdhCurve:clientGroup,timeout:4000,enableTrace:process.env.TRACE_TLS==='1'},()=>{
        entry.client_tls={protocol:client.getProtocol(),cipher:client.getCipher(),ephemeral:client.getEphemeralKeyInfo?.()??null,authorized:client.authorized,authorization_error:client.authorizationError||null};
        client.write('GET /owned-lab HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n');
      });}catch(e){entry.client_error={code:e.code||null,message:e.message};finish();return;}
      let raw='';client.on('data',chunk=>raw+=chunk.toString());
      client.on('error',e=>{entry.client_error={code:e.code||null,message:e.message};finish();});
      client.on('timeout',()=>{entry.client_error={code:'TIMEOUT',message:'client timeout'};client.destroy();finish();});
      client.on('close',()=>{entry.client_response=raw;entry.application_success=raw.includes('HTTP/1.1 200 OK')&&raw.includes('owned-lab-ok');finish();});
    });
  }catch(e){entry.setup_error={code:e.code||null,message:e.message};}
  finally{
    if(server){await new Promise(resolve=>server.close(resolve));entry.closed_at=now();entry.listener_closed=!server.listening;}
    entry.finished_utc=now();record.phases.push(entry);
  }
  return entry;
}
(async()=>{
  const classical=await phase('classical_x25519','X25519','X25519',true);
  const hybrid=await phase('hybrid_x25519mlkem768','X25519MLKEM768','X25519MLKEM768',true);
  if(!hybrid.setup_error){
    await phase('classical_only_client_against_hybrid','X25519MLKEM768','X25519',false);
  }else record.hybrid_unsupported_reason=hybrid.setup_error;
  const pure=await phase('pure_mlkem768','MLKEM768','MLKEM768',true);
  if(pure.setup_error)record.pure_unsupported_reason=pure.setup_error;
  const rollback=await phase('rollback_x25519','X25519','X25519',true);
  record.finished_utc=now();record.actual_application_success={classical:!!classical.application_success,hybrid:!!hybrid.application_success,rollback:!!rollback.application_success};
  record.classical_client_refused_hybrid=record.phases.find(x=>x.name==='classical_only_client_against_hybrid')?.application_success===false;
  fs.writeFileSync(process.env.TLS_OUT||path.join(root,'raw/transition.json'),JSON.stringify(record,null,2)+'\n');
  console.log(JSON.stringify({success:record.actual_application_success,hybrid_unsupported:!!record.hybrid_unsupported_reason,pure_unsupported:!!record.pure_unsupported_reason,refused:record.classical_client_refused_hybrid,phases:record.phases.map(x=>({name:x.name,setup_error:x.setup_error,application_success:x.application_success,client_ephemeral:x.client_tls?.ephemeral,server_ephemeral:x.connections[0]?.ephemeral}))}));
  if(!classical.application_success||!rollback.application_success)process.exitCode=1;
  if(hybrid.application_success&&record.classical_client_refused_hybrid!==true)process.exitCode=1;
})().catch(e=>{console.error(e.stack);process.exitCode=1;});
