<?php
declare(strict_types=1);namespace Aen\RateLab;
final class HttpCapture {
 public static function run():array {
  $port=8411;$socket=@stream_socket_server("tcp://127.0.0.1:$port",$errno,$errstr);
  if(!$socket)throw new \RuntimeException('Port8411 busy; stop only your own lab');fclose($socket);
  $env=getenv();$env['AEN_LAB_API']='1';$env['AEN_BACKEND']='files';$env['AEN_NAMESPACE']='aen_http_'.bin2hex(random_bytes(5));
  $log=dirname(__DIR__).'/var/http-capture.log';if(!is_dir(dirname($log)))mkdir(dirname($log),0770,true);
  $proc=proc_open([PHP_BINARY,'-S',"127.0.0.1:$port",'-t',dirname(__DIR__).'/public',dirname(__DIR__).'/server/router.php'],[0=>['pipe','r'],1=>['file',$log,'a'],2=>['file',$log,'a']],$pipes,null,$env);
  if(!is_resource($proc))throw new \RuntimeException('Cannot start HTTP server');fclose($pipes[0]);
  $url="http://127.0.0.1:$port/api.php";
  try{
   $ready=false;for($i=0;$i<40;$i++){if(@file_get_contents($url)!==false){$ready=true;break;}usleep(50000);}if(!$ready)throw new \RuntimeException('HTTP not ready');
   $start=microtime(true);$events=[];
   for($i=0;$i<3;$i++){
    if($i===2)sleep(max(1,$events[1]['retry_header']));
    $context=stream_context_create(['http'=>['method'=>'POST','header'=>"Content-Type: application/json\r\nX-Demo-Token: demo-alice\r\n",'content'=>'{"operation":"report"}','ignore_errors'=>true,'timeout'=>5]]);
    $raw=file_get_contents($url,false,$context);$headers=$http_response_header??[];preg_match('/\s(\d{3})\s/',$headers[0]??'',$m);$status=(int)($m[1]??0);
    $body=json_decode($raw,true,16,JSON_THROW_ON_ERROR);$retry=0;foreach($headers as $h)if(preg_match('/^Retry-After:\s*(\d+)$/i',$h,$m))$retry=(int)$m[1];
    $events[]=$body+['status'=>$status,'retry_header'=>$retry,'t_ms'=>round((microtime(true)-$start)*1000,2)];
   }
   if(array_column($events,'status')!==[200,429,200])throw new \RuntimeException('Unexpected HTTP behavior');
   return ['id'=>'http429','title'=>'HTTP 429 и повтор по Retry-After','explanation'=>'Настоящие HTTP-запросы к собственному PHP API. После отказа клиент дождался заголовка Retry-After.','config'=>Lab::policy('token_bucket',4,2,2),'backend'=>'files + FlockStore','events'=>$events];
  }finally{proc_terminate($proc);proc_close($proc);}
 }
}
