<?php
require __DIR__.'/schema-api-common.php';
$check(is_dir($schemaDir)&&!file_exists($schemaDir.'/baseline.json'),'Fresh new API namespace');
$http=0;$dml=0;$serverReads=0;$clockWindows=[];
$countDml=static function($entries){return count(array_filter($entries,static function($r){return preg_match('/^\s*(INSERT|UPDATE|DELETE)\b/i',$r['queryString']);}));};
$expectedBase=json_decode(file_get_contents($schemaDir.'/expected-baseline.json'),true);
$base=$schemaSource();$check($base===$expectedBase,'Fresh approved complete old baseline');$check(count($base['material_category'])===($lane==='B'?36:5),'Old Material exact row count');
$check($sq('SELECT ID FROM '.$p.'material_category WHERE NAME LIKE ?',[$marker.'%'])===[],'New marker collision0');
require_once __DIR__.'/source/application/base/Security.php';$auth=json_decode(file_get_contents(__DIR__.'/private-request.json'),true);$parts=explode("\t",\app\base\Security::decrypt($auth['token']));$actor=$sq('SELECT * FROM '.$p.'user WHERE ID=?',[$ref['actor_id']])[0];
$check(count($parts)>=7&&(string)$actor['id']===$parts[0]&&$actor['uuid']===$parts[1]&&(string)$actor['account']===$parts[2],'Existing normal Auth same actor');$creator=$parts[2];$check($creator==='admin'&&strlen($creator)===5,'Fresh actual creator admin5');
$ssave('preflight.json',['lane'=>$lane,'marker'=>$marker,'creator'=>$creator,'creator_sha256'=>hash('sha256',$creator),'identity_sha256'=>hash('sha256',json_encode($actor,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)),'database'=>$lane==='B'?$sq('SELECT DATABASE() AS DB,VERSION() AS VERSION,@@SESSION.SQL_MODE AS SQL_MODE'):$sq("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') AS DB FROM DUAL"),'collision'=>0]);
$ssave('baseline.json',$base);$ssave('lease.json',[]);$sourceLock=[];foreach(json_decode(file_get_contents(__DIR__.'/private-source-lock.json'),true)as $file=>$old)$sourceLock[$file]=hash_file('sha256',__DIR__.'/source/application/'.$file);$ssave('source-lock.json',$sourceLock);
$budget=static function()use(&$schemaReads,&$serverReads,$check){$check($schemaReads+$serverReads<=320,'Approved SELECT cap320');};
$params=static function($name,$pid='0')use($marker){return ['pid'=>(string)$pid,'name'=>$marker.'-'.$name,'type'=>'1','status'=>'1','leaf_flag'=>'1','is_delete'=>'0'];};
$permit=static function($kind,$data,$ids=null){$a=['kind'=>$kind,'table'=>'material_category','data'=>array_map('strval',$data)];if($ids!==null)$a['where']=['id',$ids];return $a;};
$api=static function($label,$path,$post,$allowed,$expectedDml)use($schemaSource,$sguard,$slease,$ssave,$sclock,$schemaDir,$lane,$auth,$check,$countDml,$budget,&$http,&$dml,&$serverReads){
 $check(!file_exists($schemaDir.'/'.$label.'.sent.json'),'No sent replay');$before=$schemaSource();$sguard($before,$slease());$beforeClock=$sclock();
 $phase=['label'=>$label,'nonce'=>bin2hex(random_bytes(20)),'path'=>$path,'params'=>$post,'allowed'=>$allowed];$ssave('phase.json',$phase);$ssave($label.'.sent.json',['path'=>$path,'params'=>$post,'clock'=>$beforeClock]);$http++;
 $c=curl_init('http://127.0.0.1:'.($lane==='B'?18321:18322).$path);$headers=[];curl_setopt_array($c,[CURLOPT_POST=>true,CURLOPT_POSTFIELDS=>http_build_query($post),CURLOPT_RETURNTRANSFER=>true,CURLOPT_HTTPHEADER=>['token: '.$auth['token'],'X-CDX-CRUD: '.$phase['nonce'],'X-CDX-Scope: schema-api-evidence'],CURLOPT_CONNECTTIMEOUT=>5,CURLOPT_TIMEOUT=>30,CURLOPT_HEADERFUNCTION=>static function($c,$line)use(&$headers){if(preg_match('/^(Content-Type|X-Powered-By):/i',$line))$headers[]=$line;return strlen($line);}]);$body=curl_exec($c);$info=curl_getinfo($c);$error=curl_error($c);curl_close($c);
 $wirePath=$schemaDir.'/'.$label.'.wire.json';$check(is_file($wirePath),'Complete server wire');$wire=json_decode(file_get_contents($wirePath),true);$serverReads+=$wire['SELECT'];$actualDml=$countDml($wire['prepared_SQL']);$dml+=$actualDml;
 $after=$schemaSource();$sguard($after,$slease());$afterClock=$sclock();$decoded=json_decode((string)$body,true);
 $ssave($label.'.result.json',['HTTP'=>$info['http_code'],'body'=>$body,'body_sha256'=>hash('sha256',(string)$body),'headers'=>$headers,'curl_error'=>$error,'client_before'=>$before,'independent_after'=>$after,'clock_before'=>$beforeClock,'clock_after'=>$afterClock,'DML'=>$actualDml,'duration_seconds'=>$info['total_time']]);
 $check($info['http_code']===200&&is_array($decoded)&&$decoded['code']===0&&is_string($decoded['message'])&&is_array($decoded['data']),'Exact successful response type');$check($actualDml===$expectedDml&&$wire['remaining_allowances']===[],'All and only exact API DML');$check($after===$wire['source_after']&&$before===$wire['source_before'],'Independent full source equals server');$budget();
 echo json_encode(['lane'=>$lane,'label'=>$label,'HTTP'=>$info['http_code'],'DML'=>$actualDml]),"\n";flush();return ['before'=>$before,'after'=>$after,'clock_before'=>$beforeClock,'clock_after'=>$afterClock,'body'=>$decoded];
};
$direct=static function($label,$sql,$args,$ids,$mode)use($schemaSource,$sguard,$slease,$ssave,$sclock,$schemaDir,$db,$check,$budget,$lane,&$dml){
 $check(!file_exists($schemaDir.'/'.$label.'.started.json'),'No direct replay');$before=$schemaSource();$lease=$slease();$sguard($before,$lease);$leased=array_map('strval',array_column($lease,'id'));foreach($ids as $id)$check(in_array((string)$id,$leased,true),'Direct own leased PK');$beforeClock=$sclock();$ssave($label.'.started.json',['SQL'=>$sql,'bindings'=>$args,'source_before'=>$before,'clock_before'=>$beforeClock]);
 $stmt=$db->prepare($sql);$ok=$stmt->execute($args);$dml++;$check($ok,'Direct SQL success');$after=$schemaSource();$sguard($after,$lease);$afterClock=$sclock();$ssave($label.'.result.json',['SQL'=>$sql,'bindings'=>$args,'rowCount'=>$stmt->rowCount(),'source_before'=>$before,'source_after'=>$after,'clock_before'=>$beforeClock,'clock_after'=>$afterClock,'mode'=>$mode]);
 foreach($before['material_category']as $i=>$row){$new=$after['material_category'][$i];if(!in_array((string)$row['id'],array_map('strval',$ids),true))$check($new===$row,'Direct no other row impact');else{
  if($mode==='noop')$check($new===$row,'NoOp physical full row/time exact');
  elseif($mode==='reset'){$want=$row;$want['update_time']='2001-01-01 01:01:01';$check($new===$want,'Only exact timestamp reset');}
  elseif($mode==='explicit'){$want=$row;$want['status']=$new['status'];$check((int)$new['status']===0,'Explicit status0');$want['update_time']='2002-02-02 02:02:02';$check($new===$want,'Explicit timestamp honored');}
  else{$want=$row;$want['status']=$new['status'];$check((int)$new['status']===1&&$row['update_time']==='2002-02-02 02:02:02','Self timestamp status1');$check($new===$want,'Explicit self timestamp preserved');}
 }}$budget();echo json_encode(['lane'=>$lane,'label'=>$label,'DML'=>1,'rowCount'=>$stmt->rowCount()]),"\n";flush();return $after;
};
$timeInWindow=static function($row,$result)use($check){foreach(['create_time','update_time']as $key)$check(is_string($row[$key])&&strlen($row[$key])===19,'Native seconds string');$check($row['update_time']>=$result['clock_before']&&$row['update_time']<=$result['clock_after'],'DB timestamp in local window');};
try{
 $r=$api('A1','/p/MaterialCategory/add',$params('P1'),[$permit('insert',$params('P1')+['create_by'=>$creator,'level'=>'1','category_path'=>''])],1);$p1=$sown($r['after'],'P1');$timeInWindow($p1,$r);
 $r=$api('A2','/p/MaterialCategory/add',$params('P2'),[$permit('insert',$params('P2')+['create_by'=>$creator,'level'=>'1','category_path'=>''])],1);$p2=$sown($r['after'],'P2');$timeInWindow($p2,$r);
 $resetSql='UPDATE '.$p.'material_category SET UPDATE_TIME=? WHERE ID=?';$old='2001-01-01 01:01:01';
 $direct('D1',$resetSql,[$old,$p1['id']],[$p1['id']],'reset');
 $post=$params('L',$p1['id']);$r=$api('A3','/p/MaterialCategory/add',$post,[$permit('update',['leaf_flag'=>'0'],[$p1['id']]),$permit('insert',$post+['create_by'=>$creator,'level'=>'2','category_path'=>(string)$p1['id']])],2);$leaf=$sown($r['after'],'L');$timeInWindow($leaf,$r);$timeInWindow($sown($r['after'],'P1'),$r);
 foreach([['D2',$p1['id']],['D3',$p2['id']],['D4',$leaf['id']]]as $entry)$direct($entry[0],$resetSql,[$old,$entry[1]],[$entry[1]],'reset');
 $post=$params('L-U',$p2['id']);$post['id']=(string)$leaf['id'];$data=$post;unset($data['id'],$data['type']);$data['level']='2';$data['category_path']=(string)$p2['id'];
 $r=$api('A4','/p/MaterialCategory/update',$post,[$permit('update',['leaf_flag'=>'0'],[$p2['id']]),$permit('update',['leaf_flag'=>'1'],[$p1['id']]),$permit('update',$data,[$leaf['id']])],3);foreach(['P1','P2','L-U']as $suffix)$timeInWindow($sown($r['after'],$suffix),$r);
 $r=$api('A5','/p/MaterialCategory/read',['id'=>(string)$leaf['id']],[],0);$read=$r['body']['data'];$check($read['pname']===$marker.'-P2'&&strlen($read['create_time'])===19&&strlen($read['update_time'])===19,'Actual HTTP read seconds + own pname');
 $ids=[$p1['id'],$p2['id'],$leaf['id']];$direct('D5','UPDATE '.$p.'material_category SET UPDATE_TIME=? WHERE ID IN (?,?,?)',array_merge([$old],$ids),$ids,'reset');
 $direct('D6','UPDATE '.$p.'material_category SET ID=ID,PID=PID,NAME=NAME,CATEGORY_PATH=CATEGORY_PATH,LEVEL=LEVEL,STATUS=STATUS,LEAF_FLAG=LEAF_FLAG,TYPE=TYPE,IS_DELETE=IS_DELETE,CREATE_TIME=CREATE_TIME,CREATE_BY=CREATE_BY WHERE ID=?',[$p2['id']],[$p2['id']],'noop');
 $direct('D7','UPDATE '.$p.'material_category SET STATUS=?,UPDATE_TIME=? WHERE ID=?',[0,'2002-02-02 02:02:02',$p2['id']],[$p2['id']],'explicit');
 $state=$direct('D8','UPDATE '.$p.'material_category SET STATUS=?,UPDATE_TIME=UPDATE_TIME WHERE ID=?',[1,$p2['id']],[$p2['id']],'self');
 $closure=[];foreach($ids as $id){$desc=$sq('SELECT ID FROM '.$p.'material_category WHERE CATEGORY_PATH LIKE ? AND STATUS=1 AND IS_DELETE=0',['%'.$id.'%']);$closure=array_merge($closure,array_column($desc,'id'),[$id]);}$closed=array_values(array_unique(array_map('strval',$closure)));$want=array_map('strval',$ids);sort($closed);sort($want);$check($closed===$want,'Original LIKE closure only new own3');$check((int)$sq('SELECT COUNT(*) AS CNT FROM '.$p.'material WHERE CATEGORY_ID IN (?,?,?)',$ids)[0]['cnt']===0,'Material references0');$ssave('del-closure.json',['own_ids'=>$ids,'original_closure'=>$closure,'reference_count'=>0]);
 $r=$api('A6','/p/MaterialCategory/del',['ids'=>implode(',',$ids)],[$permit('update',['is_delete'=>'1'],$closure)],1);foreach(['P1','P2','L-U']as $suffix){$row=$sown($r['after'],$suffix);$check((int)$row['is_delete']===1,'Only new3 softdeleted');$timeInWindow($row,$r);}
 $final=$schemaSource();$sguard($final,$slease());$check(count($slease())===3&&count($final['material_category'])===($lane==='B'?39:8),'Final exact old+new3');$check($http===6&&$dml===16,'Exact approved HTTP6/DML16');$budget();
 $ssave('final.json',['source'=>$final,'lease'=>$slease(),'HTTP'=>$http,'DML'=>$dml,'SELECT'=>$schemaReads+$serverReads,'business_old_source_exact'=>true,'new3_softdeleted'=>true]);$ssave('client-readonly-SQL.json',$schemaQueries);
 echo json_encode(['lane'=>$lane,'passed'=>true,'HTTP'=>$http,'DML'=>$dml,'SELECT'=>$schemaReads+$serverReads]),"\n";
}catch(Throwable $e){$ssave('stopped.json',['class'=>get_class($e),'message'=>$e->getMessage(),'HTTP'=>$http,'DML'=>$dml,'SELECT'=>$schemaReads+$serverReads]);echo json_encode(['lane'=>$lane,'stopped'=>true,'message'=>$e->getMessage(),'HTTP'=>$http,'DML'=>$dml]),"\n";exit(1);}
