<?php
require_once __DIR__.'/db.php';
$marker='CDXNW11D6A2';
$source=static function()use($q,$p,$lane):array {
 $out=[];foreach(['nutrition_time','nutrition_set','nutrition_category','nutrition_template','nutrition_template_ext','nutrition_station','nutrition_station_ext'] as $table)$out[$table]=$q('SELECT * FROM '.$p.$table.' ORDER BY ID');
 $uuid=$lane==='B'?'6969DC3F-CC71-237D-FCED-389B86C5905F':'711DB31A-5BF6-4478-BB9E-C866F0C88DA3';$out['prior_product']=$q('SELECT * FROM '.$p.'nutrition WHERE UUID=?',[$uuid]);
 $actor=$q('SELECT * FROM '.$p.'user WHERE ID=1');if(count($actor)!==1||(int)$actor[0]['type']!==0||(int)$actor[0]['is_delete']!==0)throw new RuntimeException('Normal actor');$out['actor_sha256']=hash('sha256',json_encode($actor,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION));return $out;
};
$original=static function():array {
 $out=json_decode(file_get_contents(__DIR__.'/private-protected-source.json'),true);foreach(['nutrition_time','nutrition_set'] as $t)$out[$t]=json_decode(file_get_contents(__DIR__.'/private-'.$t.'-rows.json'),true);return $out;
};
$guard=static function(array $now)use($original,$marker,$check):array {
 $base=$original();$own=[];foreach(['nutrition_time','nutrition_set'] as $table){$own[$table]=[];$natural=[];foreach($now[$table] as $row){if(strpos($row['name'],$marker.'-')===0)$own[$table][]=$row;else $natural[]=$row;}$check(count($own[$table])<=1,'Only one own entity '.$table);$check($natural===$base[$table],'Complete natural table unchanged '.$table);unset($now[$table],$base[$table]);}ksort($now);ksort($base);$check($now===$base,'Complete protected source unchanged');return $own;
};
function cdxCase(int $step,array $ids):array {
 $t=$ids['nutrition_time']??'';$s=$ids['nutrition_set']??'';$m='CDXNW11D6A2';$spec=[
 1=>['nutrition_time','add',['name'=>$m.'-time-A','order_no'=>'620001','function'=>$m.'-function-A']],
 2=>['nutrition_time','update',['uuid'=>$t,'name'=>$m.'-time-B','order_no'=>'620002','function'=>$m.'-function-B']],
 3=>['nutrition_set','add',['name'=>$m.'-set-A','order_no'=>'620001','use_time'=>$t]],
 4=>['nutrition_set','update',['uuid'=>$s,'name'=>$m.'-set-B','order_no'=>'620002','use_time'=>$t]],
 5=>['nutrition_time','delete',['uuid'=>$t]],6=>['nutrition_time','able',['uuid'=>$t,'status'=>'0']],7=>['nutrition_time','able',['uuid'=>$t,'status'=>'0']],
 8=>['nutrition_set','able',['uuid'=>$s,'status'=>'0']],9=>['nutrition_set','able',['uuid'=>$s,'status'=>'0']],10=>['nutrition_set','delete',['uuid'=>$s]],11=>['nutrition_time','delete',['uuid'=>$t]]];
 if(!isset($spec[$step]))throw new RuntimeException('Unknown step');[$table,$action,$params]=$spec[$step];return ['step'=>$step,'table'=>$table,'action'=>$action,'path'=>'/p/'.$table.'/'.$action,'params'=>$params];
}
$transition=static function(array $before,array $after,array $case,int $began,int $ended)use($guard,$check,$marker,$q,$p):array {
 $bo=$guard($before);$ao=$guard($after);$table=$case['table'];$step=$case['step'];$other=$table==='nutrition_time'?'nutrition_set':'nutrition_time';$check($bo[$other]===$ao[$other],'Other owned entity unchanged');
 if(in_array($step,[1,3],true)){
  $check($bo[$table]===[]&&count($ao[$table])===1,'Exactly one new entity');$row=$ao[$table][0];$keys=$table==='nutrition_time'?['id','uuid','name','function','order_no','status','del_flag','create_time','create_by']:['id','uuid','name','number','status','is_del','create_time','create_by','order_no','use_time'];$actual=array_keys($row);sort($actual);sort($keys);$check($actual===$keys,'Complete new columns');
  $check(preg_match('/^[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}$/D',$row['uuid'])===1&&(int)$row['id']>0,'Generated UUID/PK');
  $check(hash('sha256',(string)$row['create_by'])==='efcac9c3ed28940cbd075c4b8bdd20c5a6165984c1f413546f9620b5e8b9d044','Business creator actual name');$date=preg_replace('/\.0{1,6}$/','',$row['create_time']);$clock=strtotime($date);$check($clock>=$began-1&&$clock<=$ended+1,'Actual API creation clock');
  $check((int)$row['status']===1&&(int)$row['order_no']===620001,'Database defaults status/order');$check($table==='nutrition_time'?(int)$row['del_flag']===0:((int)$row['number']===0&&(int)$row['is_del']===1),'Database lifecycle defaults');
  foreach($case['params'] as $field=>$value)$check((string)$row[$field]===$value,'New requested field '.$field);
  $check((int)$q('SELECT COUNT(*) AS CNT FROM '.$p.$table.' WHERE UUID=?',[$row['uuid']])[0]['cnt']===1,'Independent generated UUID one row');
 }else{
  $check(count($bo[$table])===1&&count($ao[$table])===1,'Single owned entity');$expected=$bo[$table][0];$changes=[];
  if(in_array($step,[2,4],true))$changes=$case['params'];elseif(in_array($step,[6,7,8,9],true))$changes=['status'=>'0'];elseif($step===10)$changes=['is_del'=>'0'];elseif($step===11)$changes=['del_flag'=>'1'];
  foreach($changes as $field=>$value){$check((string)$ao[$table][0][$field]===$value,'Exact changed value '.$field);$expected[$field]=$ao[$table][0][$field];}$check($expected===$ao[$table][0],'All non-whitelisted columns unchanged');
  if(in_array($step,[5,7,9],true))$check($bo===$ao,'Reject/no-op complete rows unchanged');
 }
 $ids=[];foreach($ao as $t=>$rows)if($rows)$ids[$t]=$rows[0]['uuid'];
 if(isset($ids['nutrition_time'])){$check((int)$q('SELECT COUNT(*) AS CNT FROM '.$p.'nutrition WHERE IS_DEL=1 AND USE_TIME LIKE ?', ['%'.$ids['nutrition_time'].'%'])[0]['cnt']===0,'No product time references');$refs=(int)$q('SELECT COUNT(*) AS CNT FROM '.$p.'nutrition_set WHERE IS_DEL=1 AND USE_TIME=?',[$ids['nutrition_time']])[0]['cnt'];$check($refs===(isset($ids['nutrition_set'])&&$step<10?1:0),'Only own active Set references Time');}
 if(isset($ids['nutrition_set']))$check((int)$q('SELECT COUNT(*) AS CNT FROM '.$p.'nutrition WHERE SET_UUID=?',[$ids['nutrition_set']])[0]['cnt']===0,'No product Set references');return $ids;
};
