<?php

declare(strict_types=1);

// REVIEW DRAFT. Five short-lived synthetic business rows; no execution without root approval.
if ((string)getenv('CDXPARCF_EXECUTE') !== 'ROOT_APPROVED_EXACT_SHA') {
    fwrite(STDERR,"Review draft; execution disabled\n");
    exit(2);
}
set_exception_handler(static function (Throwable $error): void {
    fwrite(STDERR,'CDXPARCF_PRECHECK_FAILED '.get_class($error)
        .' code='.(string)$error->getCode().PHP_EOL);
    exit(2);
});
$lane=(string)getenv('CDXPARCF_LANE');
$root=(string)getenv('POC_APP_ROOT');
$base=rtrim((string)getenv('POC_BASE_URL'),'/');
$runtimes=[
    'A'=>['/tmp/zhct-http-store-a.l5omH8','http://127.0.0.1:18097'],
    'B'=>['/tmp/zhct-http-store-mysql.dQTTBP','http://127.0.0.1:18081'],
    'C'=>['/tmp/zhct-dm-poc-20260928.fcpiiN/store','http://127.0.0.1:18080'],
];
if (!isset($runtimes[$lane]) || $root!==$runtimes[$lane][0]
    || $base!==$runtimes[$lane][1]
    || !is_file($root.'/application/base/Security.php')) {
    throw new RuntimeException('Approved isolated Store runtime required');
}
$boundary=json_decode((string)file_get_contents($base.'/__poc_boundary'),true);
if (!is_array($boundary) || empty($boundary['external_stubs'])
    || empty($boundary['redis_isolated']) || !empty($boundary['real_queue'])) {
    throw new RuntimeException('Store isolation boundary missing');
}

if ($lane==='C') {
    if ((string)getenv('POC_DIALECT')!=='dm') {
        throw new RuntimeException('C DM dialect required');
    }
    $pid=(string)getenv('POC_RUNTIME_PID');
    $cmdline=ctype_digit($pid)
        ? (string)file_get_contents('/proc/'.$pid.'/cmdline') : '';
    if (!ctype_digit($pid) || strpos($cmdline,'127.0.0.1:18080')===false
        || strpos($cmdline,$root.'/public')===false) {
        throw new RuntimeException('C PID/port/docroot mismatch');
    }
    $context=array_fill_keys(['POC_HOST','POC_PORT','POC_SCHEMA',
        'POC_USER','POC_PASSWORD'],'');
    foreach ($context as $key=>$_) $context[$key]=(string)getenv($key);
    if ($context['POC_HOST']==='') {
        foreach (explode("\0",(string)file_get_contents('/proc/'.$pid.'/environ')) as $entry) {
            $pair=explode('=',$entry,2);
            if (count($pair)===2 && array_key_exists($pair[0],$context)) {
                $context[$pair[0]]=$pair[1];
            }
        }
    }
    if ($context['POC_HOST']!=='127.0.0.1'
        || $context['POC_PORT']!=='5237'
        || strtoupper($context['POC_SCHEMA'])!=='ZHCT_APP'
        || strtoupper($context['POC_USER'])!=='ZHCT_APP'
        || $context['POC_PASSWORD']==='') {
        throw new RuntimeException('Unexpected C target');
    }
    $dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
    $open=static function () use ($dsn,$context): PDO {
        return new PDO($dsn,$context['POC_USER'],$context['POC_PASSWORD'],[
            PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_EMULATE_PREPARES=>false,
            PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
        ]);
    };
    $table=static function (string $name): string { return strtoupper($name); };
} else {
    if ((string)getenv('POC_DIALECT')!=='mysql') {
        throw new RuntimeException('Code local MySQL dialect required');
    }
    $localPath=realpath(__DIR__
        . '/../../../../../zhctproject/store/application/config/local/database.php');
    if (!$localPath || strpos($localPath,
        '/zhctproject/store/application/config/local/')===false) {
        throw new RuntimeException('Approved local database config absent');
    }
    $load=static function (string $path): array {
        $data=require $path;
        if (!is_array($data)) throw new RuntimeException('Invalid DB config');
        return $data;
    };
    $local=$load($localPath);
    $selected=$load($root.'/application/database.php');
    foreach (['hostname','database','username','password'] as $field) {
        if (!isset($local[$field],$selected[$field])
            || $local[$field]!==$selected[$field]) {
            throw new RuntimeException('A/B DB differs from code local');
        }
    }
    if ((int)($local['hostport']??3306)
        !==(int)($selected['hostport']??3306)) {
        throw new RuntimeException('A/B DB port differs from code local');
    }
    $dsn='mysql:host='.$local['hostname'].';port='.(int)($local['hostport']??3306)
        .';dbname='.$local['database'].';charset=utf8mb4';
    $open=static function () use ($dsn,$local): PDO {
        return new PDO($dsn,(string)$local['username'],(string)$local['password'],[
            PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_EMULATE_PREPARES=>false,
            PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC,
            PDO::ATTR_TIMEOUT=>8,
        ]);
    };
    $table=static function (string $name): string { return strtolower($name); };
}

function cdxCfUuid(): string
{
    $bytes=random_bytes(16);
    $bytes[6]=chr((ord($bytes[6])&0x0f)|0x40);
    $bytes[8]=chr((ord($bytes[8])&0x3f)|0x80);
    $hex=strtoupper(bin2hex($bytes));
    return substr($hex,0,8).'-'.substr($hex,8,4).'-'.substr($hex,12,4)
        .'-'.substr($hex,16,4).'-'.substr($hex,20,12);
}
function cdxCfRows(PDO $db,string $sql,array $args=[]): array
{
    $stmt=$db->prepare($sql);
    $stmt->execute($args);
    return array_map(static function (array $row): array {
        return array_change_key_case($row,CASE_LOWER);
    },$stmt->fetchAll(PDO::FETCH_ASSOC));
}
function cdxCfCount(PDO $db,string $sql,array $args=[]): int
{
    return (int)(cdxCfRows($db,$sql,$args)[0]['n']??-1);
}
function cdxCfPost(string $base,string $route,array $form,string $token=''): array
{
    $headers="Content-Type: application/x-www-form-urlencoded\r\n";
    if ($token!=='') $headers.='token: '.$token."\r\n";
    $context=stream_context_create(['http'=>[
        'method'=>'POST','header'=>$headers,
        'content'=>http_build_query($form,'','&',PHP_QUERY_RFC3986),
        'timeout'=>20,'ignore_errors'=>true,
    ]]);
    $body=@file_get_contents($base.$route,false,$context);
    $responseHeaders=$http_response_header??[];
    if (strpos((string)($responseHeaders[0]??''),' 200 ')===false
        || !is_string($body)) {
        throw new RuntimeException('Isolated HTTP transport failed');
    }
    $json=json_decode($body,true);
    if (!is_array($json)) throw new RuntimeException('Isolated HTTP not JSON');
    return $json;
}
function cdxCfContainsName($node,string $name): bool
{
    if (is_string($node)) return $node===$name;
    if (!is_array($node)) return false;
    foreach ($node as $value) {
        if (cdxCfContainsName($value,$name)) return true;
    }
    return false;
}
function cdxCfFindRow($node,string $name): ?array
{
    if (!is_array($node)) return null;
    if (($node['name']??null)===$name) return $node;
    foreach ($node as $child) {
        $found=cdxCfFindRow($child,$name);
        if ($found!==null) return $found;
    }
    return null;
}
function cdxCfHasUnique(PDO $db,string $lane,string $schema,
    string $table,array $expected): bool
{
    if ($lane==='C') {
        $rows=cdxCfRows($db,
            'SELECT i.INDEX_NAME,i.UNIQUENESS,ic.COLUMN_NAME,ic.COLUMN_POSITION'
            .' FROM USER_INDEXES i JOIN USER_IND_COLUMNS ic'
            .' ON i.INDEX_NAME=ic.INDEX_NAME WHERE i.TABLE_NAME=?'
            .' ORDER BY i.INDEX_NAME,ic.COLUMN_POSITION',[strtoupper($table)]);
    } else {
        $rows=cdxCfRows($db,
            'SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME'
            .' FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=?'
            .' AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',
            [$schema,strtolower($table)]);
    }
    $indexes=[];
    foreach ($rows as $row) {
        $name=(string)$row['index_name'];
        $indexes[$name]['unique']=$lane==='C'
            ? strtoupper((string)$row['uniqueness'])==='UNIQUE'
            : (int)$row['non_unique']===0;
        $indexes[$name]['columns'][]=strtolower((string)$row['column_name']);
    }
    foreach ($indexes as $index) {
        if ($index['unique'] && $index['columns']===$expected) return true;
    }
    return false;
}

$db=$open();
if ($lane==='C') {
    if (strtoupper((string)$db->query(
        "SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")
        ->fetchColumn())!=='ZHCT_APP') {
        throw new RuntimeException('Wrong C schema');
    }
} elseif (strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')===false) {
    throw new RuntimeException('Wrong A/B MySQL version');
}
$marker='CDXPARCF'.strtoupper(bin2hex(random_bytes(4)));
$day='2001-01-02';
$foodName=$marker.'-FOOD';
$dishName=$marker.'-DISH';
$foodId=0;
$dishId=0;
$restaurantId=0;
$userId=0;
$roleId=0;
$userUuid=cdxCfUuid();
$roleUuid=cdxCfUuid();
$dishUuid=cdxCfUuid();
$componentUuid=cdxCfUuid();
$recipeUuid=cdxCfUuid();
$dateMenuUuid=cdxCfUuid();
$fakeStaffUuid=cdxCfUuid();
$menuUuids=[
    'cater_select'=>'C5E8BD15-C890-11DF-183B-0A5444A528EF',
    'cater_find'=>'2CBDEFF2-EADF-628F-7CBD-05A16D3183C7',
    'food_lists'=>'39288C13-FDD4-7F47-35E6-3D9B35F9CB2C',
    'food_read'=>'352B7629-DC3D-4C69-9032-DE025F25090C',
];
$names=['foods_composition','dishes','dish','recipes','date_menu',
    'user','role','user_role','role_menu','menu','restaurants',
    'dishes_custom_category'];
$tables=[];
foreach ($names as $name) $tables[$name]=$table('ydy_'.$name);
$phase='preflight';
$result=['lane'=>$lane,'marker'=>$marker,'events'=>[],'cleanup'=>[]];

try {
    $required=[
        'foods_composition'=>['id','name','category','minute_sort','energy',
            'protein','store_id','create_by','create_time','is_delete'],
        'dishes'=>['id','uuid','name','category','status','is_del','price',
            'store_id','weight','energy','protein','custom_category_id','create_by'],
        'dish'=>['id','uuid','dishes_uuid','composition_id','composition_name',
            'cook_method','composition_ratio','minute_sort'],
        'recipes'=>['id','uuid','dishes_uuid','menu_date','create_time',
            'create_by','meal_times','type','restaurant_id'],
        'date_menu'=>['id','uuid','dishes_uuid','staff_uuid','menu_date',
            'create_by','meal_type','meal_times','restaurant_id'],
        'user'=>['id','uuid','account','pwd','salt','name','type','status',
            'create_time','create_by','is_delete'],
        'role'=>['id','uuid','name','status','create_time','create_by'],
        'user_role'=>['id','user_uuid','role_uuid','create_time','create_by'],
        'role_menu'=>['id','role_uuid','menu_uuid','create_time','create_by'],
        'menu'=>['uuid','filter'],
        'restaurants'=>['id','is_delete','status'],
        'dishes_custom_category'=>['id','is_delete'],
    ];
    $inserted=[
        'foods_composition'=>['name','category','minute_sort','energy',
            'protein','store_id','create_by','create_time'],
        'dishes'=>['uuid','name','category','status','is_del','price',
            'store_id','weight','energy','protein','custom_category_id','create_by'],
        'dish'=>['uuid','dishes_uuid','composition_id','composition_name',
            'cook_method','composition_ratio','minute_sort','create_by'],
        'recipes'=>['uuid','dishes_uuid','menu_date','create_time',
            'create_by','meal_times','type','restaurant_id'],
        'date_menu'=>['uuid','dishes_uuid','staff_uuid','meal_times',
            'menu_date','create_by','meal_type','restaurant_id'],
        'user'=>['uuid','account','pwd','salt','name','type','status',
            'create_time','create_by','is_delete'],
        'role'=>['uuid','name','status','create_time','create_by'],
        'user_role'=>['user_uuid','role_uuid','create_time','create_by'],
        'role_menu'=>['role_uuid','menu_uuid','create_time','create_by'],
    ];
    foreach ($required as $key=>$fields) {
        $name=$tables[$key];
        if ($lane==='C') {
            $columns=cdxCfRows($db,'SELECT COLUMN_NAME,NULLABLE,DATA_DEFAULT'
                .' FROM USER_TAB_COLUMNS WHERE TABLE_NAME=?',[strtoupper($name)]);
            $triggers=cdxCfCount($db,
                'SELECT COUNT(*) N FROM USER_TRIGGERS WHERE TABLE_NAME=?',
                [strtoupper($name)]);
            $fks=cdxCfCount($db,"SELECT COUNT(*) N FROM USER_CONSTRAINTS"
                ." WHERE TABLE_NAME=? AND CONSTRAINT_TYPE='R'",[strtoupper($name)]);
        } else {
            $columns=cdxCfRows($db,'SELECT COLUMN_NAME,IS_NULLABLE,COLUMN_DEFAULT'
                .' FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=?'
                .' AND TABLE_NAME=?',[$local['database'],$name]);
            $triggers=cdxCfCount($db,
                'SELECT COUNT(*) N FROM information_schema.TRIGGERS'
                .' WHERE TRIGGER_SCHEMA=? AND EVENT_OBJECT_TABLE=?',
                [$local['database'],$name]);
            $fks=cdxCfCount($db,
                'SELECT COUNT(*) N FROM information_schema.KEY_COLUMN_USAGE'
                .' WHERE TABLE_SCHEMA=? AND TABLE_NAME=?'
                .' AND REFERENCED_TABLE_NAME IS NOT NULL',
                [$local['database'],$name]);
        }
        $present=array_map(static function(array $row): string {
            return strtolower((string)$row['column_name']);
        },$columns);
        if (array_diff($fields,$present) || $triggers!==0 || $fks!==0) {
            throw new RuntimeException('Required table/column/FK/trigger gate failed');
        }
        if (isset($inserted[$key])) {
            foreach ($columns as $column) {
                $columnName=strtolower((string)$column['column_name']);
                $notNull=$lane==='C'
                    ? (string)$column['nullable']==='N'
                    : (string)$column['is_nullable']==='NO';
                $default=$lane==='C' ? $column['data_default']
                    : $column['column_default'];
                if ($columnName!=='id' && $notNull && $default===null
                    && !in_array($columnName,$inserted[$key],true)) {
                    throw new RuntimeException('Synthetic insert omits required column');
                }
            }
        }
    }
    $indexSchema=$lane==='C'?'ZHCT_APP':(string)$local['database'];
    if (!cdxCfHasUnique($db,$lane,$indexSchema,$tables['role'],['name'])
        || !cdxCfHasUnique($db,$lane,$indexSchema,
            $tables['user_role'],['user_uuid','role_uuid'])
        || !cdxCfHasUnique($db,$lane,$indexSchema,
            $tables['role_menu'],['role_uuid','menu_uuid'])) {
        throw new RuntimeException('Synthetic permission unique-key gate failed');
    }
    $first=$lane==='C'?'FETCH FIRST 1 ROWS ONLY':'LIMIT 1';
    $restaurants=cdxCfRows($db,'SELECT ID FROM '.$tables['restaurants']
        .' WHERE IS_DELETE=2 AND STATUS=1 ORDER BY ID '.$first);
    if (count($restaurants)!==1 || (int)$restaurants[0]['id']<=0
        || cdxCfCount($db,'SELECT COUNT(*) N FROM '
            .$tables['dishes_custom_category']
            .' WHERE ID=1 AND IS_DELETE=0')!==1) {
        throw new RuntimeException('Safe restaurant/category reference absent');
    }
    $restaurantId=(int)$restaurants[0]['id'];
    foreach (['recipes','date_menu'] as $key) {
        if (cdxCfCount($db,'SELECT COUNT(*) N FROM '.$tables[$key]
            .' WHERE MENU_DATE=? AND RESTAURANT_ID=?',
            [$day,$restaurantId])!==0) {
            throw new RuntimeException('Historical day not empty for selected restaurant');
        }
    }
    $zeroChecks=[
        ['foods_composition','NAME',$foodName],['dishes','UUID',$dishUuid],
        ['dish','UUID',$componentUuid],['recipes','UUID',$recipeUuid],
        ['date_menu','UUID',$dateMenuUuid],['user','ACCOUNT',$marker],
        ['role','NAME',$marker],
    ];
    foreach ($zeroChecks as $check) {
        [$key,$field,$value]=$check;
        if (cdxCfCount($db,'SELECT COUNT(*) N FROM '.$tables[$key]
            .' WHERE '.$field.'=?',[$value])!==0) {
            throw new RuntimeException('Synthetic identity collision');
        }
    }
    foreach (['foods_composition','dishes'] as $key) {
        if (cdxCfCount($db,'SELECT COUNT(*) N FROM '.$tables[$key]
            .' WHERE NAME LIKE ?', ['CDXPARCF%'])!==0) {
            throw new RuntimeException('Previous synthetic CF marker residue');
        }
    }
    foreach (['user','role'] as $key) {
        $field=$key==='user'?'ACCOUNT':'NAME';
        if (cdxCfCount($db,'SELECT COUNT(*) N FROM '.$tables[$key]
            .' WHERE '.$field.' LIKE ?', ['CDXPARCF%'])!==0) {
            throw new RuntimeException('Previous synthetic actor residue');
        }
    }
    foreach (['dish','recipes','date_menu','user_role','role_menu'] as $key) {
        if (cdxCfCount($db,'SELECT COUNT(*) N FROM '.$tables[$key]
            .' WHERE CREATE_BY LIKE ?', ['CDXPARCF%'])!==0) {
            throw new RuntimeException('Previous synthetic relation residue');
        }
    }
    $menuPaths=['p/cater/select','p/cater/find','p/food/lists',
        'p/food/readbyid'];
    foreach (array_values($menuUuids) as $index=>$uuid) {
        $rows=cdxCfRows($db,'SELECT FILTER FROM '.$tables['menu']
            .' WHERE UUID=?',[$uuid]);
        if (count($rows)!==1 || !in_array($menuPaths[$index],
            array_map(static function($part): string {
                return trim(strtolower($part),' /');
            },explode('|',(string)$rows[0]['filter'])),true)) {
            throw new RuntimeException('Required type1 menu/filter absent');
        }
    }
    $result['events'][]=['step'=>'preflight','restaurant_id'=>$restaurantId,
        'historical_recipe_rows'=>0,'historical_date_menu_rows'=>0,
        'synthetic_prefix_zero'=>true,'function_menu_exact'=>4];

    $phase='synthetic_business_fixture';
    $now=date('Y-m-d H:i:s');
    $db->prepare('INSERT INTO '.$tables['foods_composition']
        .' (NAME,CATEGORY,MINUTE_SORT,ENERGY,PROTEIN,STORE_ID,CREATE_BY,CREATE_TIME)'
        .' VALUES (?,1,1,120.00,10.00,10001,?,?)')
        ->execute([$foodName,$marker,$now]);
    $foodRows=cdxCfRows($open(),'SELECT ID,NAME,ENERGY,PROTEIN,STORE_ID'
        .' FROM '.$tables['foods_composition']
        .' WHERE NAME=? AND CREATE_BY=?',[$foodName,$marker]);
    if (count($foodRows)!==1 || (int)$foodRows[0]['store_id']!==10001) {
        throw new RuntimeException('Synthetic food readback failed');
    }
    $foodId=(int)$foodRows[0]['id'];
    if ($foodId<=0) throw new RuntimeException('Synthetic food ID invalid');
    $db->prepare('INSERT INTO '.$tables['dishes']
        .' (UUID,NAME,CATEGORY,STATUS,IS_DEL,PRICE,STORE_ID,WEIGHT,ENERGY,'
        .' PROTEIN,CUSTOM_CATEGORY_ID,CREATE_BY)'
        .' VALUES (?,?,1,1,1,1.00,10001,100.00,120.00,10.00,1,?)')
        ->execute([$dishUuid,$dishName,$marker]);
    $dishRows=cdxCfRows($open(),'SELECT ID,UUID,NAME,STATUS,IS_DEL,'
        .' STORE_ID,WEIGHT,ENERGY,PROTEIN FROM '.$tables['dishes']
        .' WHERE UUID=? AND NAME=?',[$dishUuid,$dishName]);
    if (count($dishRows)!==1 || (int)$dishRows[0]['status']!==1
        || (int)$dishRows[0]['is_del']!==1
        || (int)$dishRows[0]['store_id']!==10001) {
        throw new RuntimeException('Synthetic dish readback failed');
    }
    $dishId=(int)$dishRows[0]['id'];
    $db->prepare('INSERT INTO '.$tables['dish']
        .' (UUID,DISHES_UUID,COMPOSITION_ID,COMPOSITION_NAME,COOK_METHOD,'
        .' COMPOSITION_RATIO,MINUTE_SORT,CREATE_BY) VALUES (?,?,?,?,1,100,1,?)')
        ->execute([$componentUuid,$dishUuid,$foodId,$foodName,$marker]);
    $db->prepare('INSERT INTO '.$tables['recipes']
        .' (UUID,DISHES_UUID,MENU_DATE,CREATE_TIME,CREATE_BY,MEAL_TIMES,TYPE,RESTAURANT_ID)'
        .' VALUES (?,?,?,?,?,1,1,?)')
        ->execute([$recipeUuid,$dishUuid,$day,$now,$marker,$restaurantId]);
    $db->prepare('INSERT INTO '.$tables['date_menu']
        .' (UUID,DISHES_UUID,STAFF_UUID,MEAL_TIMES,MENU_DATE,CREATE_BY,'
        .' MEAL_TYPE,RESTAURANT_ID) VALUES (?,?,?,1,?,?,3,?)')
        ->execute([$dateMenuUuid,$dishUuid,$fakeStaffUuid,$day,$marker,$restaurantId]);
    $verify=$open();
    foreach ([['dish','UUID',$componentUuid],['recipes','UUID',$recipeUuid],
        ['date_menu','UUID',$dateMenuUuid]] as $check) {
        if (cdxCfCount($verify,'SELECT COUNT(*) N FROM '.$tables[$check[0]]
            .' WHERE '.$check[1].'=?',[$check[2]])!==1) {
            throw new RuntimeException('Synthetic relation readback failed');
        }
    }
    $result['events'][]=['step'=>'synthetic_business_fixture',
        'food_rows'=>1,'dish_rows'=>1,'component_rows'=>1,
        'recipe_rows'=>1,'anonymous_date_menu_rows'=>1];

    $phase='synthetic_type1_actor';
    $db->prepare('INSERT INTO '.$tables['user']
        .' (UUID,ACCOUNT,PWD,SALT,NAME,TYPE,STATUS,CREATE_TIME,CREATE_BY,IS_DELETE)'
        .' VALUES (?,?,?,?,?,1,1,?,?,0)')
        ->execute([$userUuid,$marker,'DISABLED',
            strtoupper(bin2hex(random_bytes(8))),$marker,$now,'CODEX']);
    $users=cdxCfRows($open(),'SELECT ID,TYPE FROM '.$tables['user']
        .' WHERE UUID=? AND ACCOUNT=?',[$userUuid,$marker]);
    if (count($users)!==1 || (int)$users[0]['type']!==1) {
        throw new RuntimeException('Synthetic type1 actor readback failed');
    }
    $userId=(int)$users[0]['id'];
    require_once $root.'/application/base/Security.php';
    $token=\app\base\Security::encrypt(implode("\t",[
        (string)$userId,$userUuid,$marker,'1','','',$marker,
    ]));
    if (!is_string($token) || $token==='') {
        throw new RuntimeException('Synthetic token unavailable');
    }
    $denied=cdxCfPost($base,'/p/cater/select',
        ['keyword'=>$dishName,'page'=>1],$token);
    if (($denied['code']??null)!==1) {
        throw new RuntimeException('Type1 no-menu Cater negative failed');
    }
    $db->prepare('INSERT INTO '.$tables['role']
        .' (UUID,NAME,STATUS,CREATE_TIME,CREATE_BY) VALUES (?,?,1,?,?)')
        ->execute([$roleUuid,$marker,$now,'CODEX']);
    $roles=cdxCfRows($open(),'SELECT ID FROM '.$tables['role']
        .' WHERE UUID=? AND NAME=?',[$roleUuid,$marker]);
    if (count($roles)!==1) throw new RuntimeException('Synthetic role readback failed');
    $roleId=(int)$roles[0]['id'];
    $db->prepare('INSERT INTO '.$tables['user_role']
        .' (USER_UUID,ROLE_UUID,CREATE_TIME,CREATE_BY) VALUES (?,?,?,?)')
        ->execute([$userUuid,$roleUuid,$now,$marker]);
    foreach ($menuUuids as $uuid) {
        $db->prepare('INSERT INTO '.$tables['role_menu']
            .' (ROLE_UUID,MENU_UUID,CREATE_TIME,CREATE_BY) VALUES (?,?,?,?)')
            ->execute([$roleUuid,$uuid,$now,$marker]);
    }
    if (cdxCfCount($open(),'SELECT COUNT(*) N FROM '.$tables['role_menu']
        .' WHERE ROLE_UUID=? AND CREATE_BY=?',[$roleUuid,$marker])!==4) {
        throw new RuntimeException('Synthetic role-menu link readback failed');
    }
    $result['events'][]=['step'=>'synthetic_type1_actor',
        'no_menu_business_code'=>1,'granted_read_menu_count'=>4];

    $phase='formal_cater_reads';
    $json=cdxCfPost($base,'/p/cater/select',
        ['keyword'=>$dishName,'status'=>1,'page'=>1],$token);
    $rows=$json['data']['rows']??null;
    if (($json['code']??null)!==0 || !is_array($rows)
        || count($rows)!==1 || ($rows[0]['uuid']??null)!==$dishUuid
        || ($rows[0]['name']??null)!==$dishName) {
        throw new RuntimeException('Formal Cater select own row mismatch');
    }
    $result['events'][]=['route'=>'/p/cater/select','code'=>0,
        'own_rows'=>1,'own_row_types'=>array_map('gettype',$rows[0])];
    $json=cdxCfPost($base,'/p/cater/selectAll',
        ['keyword'=>$dishName,'status'=>1,'simple'=>0]);
    $rows=$json['data']['rows']??null;
    if (($json['code']??null)!==0 || !is_array($rows)
        || count($rows)!==1 || ($rows[0]['uuid']??null)!==$dishUuid) {
        throw new RuntimeException('Formal device Cater selectAll own row mismatch');
    }
    $result['events'][]=['route'=>'/p/cater/selectAll','code'=>0,
        'own_rows'=>1,'own_row_types'=>array_map('gettype',$rows[0])];
    $json=cdxCfPost($base,'/p/cater/find',
        ['uuid'=>$dishUuid,'flag'=>1],$token);
    $item=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($item)
        || ($item['uuid']??null)!==$dishUuid
        || !is_array($item['data']??null)
        || count($item['data'])!==1
        || (int)($item['data'][0]['composition_id']??0)!==$foodId) {
        throw new RuntimeException('Formal Cater find own dish/component mismatch');
    }
    $result['events'][]=['route'=>'/p/cater/find','code'=>0,
        'own_dish'=>1,'own_component'=>1,
        'own_row_types'=>array_map('gettype',$item)];

    $phase='formal_food_reads';
    $json=cdxCfPost($base,'/p/food/lists',
        ['name'=>$foodName,'page'=>1,'pagesize'=>10],$token);
    $rows=$json['data']['rows']??null;
    if (($json['code']??null)!==0 || !is_array($rows)
        || count($rows)!==1 || ($rows[0]['name']??null)!==$foodName
        || (int)($rows[0]['id']??0)!==$foodId) {
        throw new RuntimeException('Formal Food lists own row mismatch');
    }
    $result['events'][]=['route'=>'/p/food/lists','code'=>0,
        'own_rows'=>1,'own_row_types'=>array_map('gettype',$rows[0])];
    $json=cdxCfPost($base,'/p/food/readById',['id'=>$foodId],$token);
    $item=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($item)
        || ($item['name']??null)!==$foodName
        || (int)($item['id']??0)!==$foodId) {
        throw new RuntimeException('Formal Food readById own row mismatch');
    }
    $result['events'][]=['route'=>'/p/food/readById','code'=>0,
        'own_rows'=>1,'own_row_types'=>array_map('gettype',$item)];
    $json=cdxCfPost($base,'/p/food/is_use_food',['id'=>$foodId],$token);
    if (($json['code']??null)!==1
        || cdxCfCount($open(),'SELECT COUNT(*) N FROM '.$tables['dish']
            .' WHERE UUID=? AND DISHES_UUID=? AND COMPOSITION_ID=?',
            [$componentUuid,$dishUuid,$foodId])!==1) {
        throw new RuntimeException('Formal Food in-use branch mismatch');
    }
    $result['events'][]=['route'=>'/p/food/is_use_food',
        'expected_occupied_code'=>1,'own_dish_component_refs'=>1];

    $phase='formal_restaurant_reads';
    $baseForm=['restaurant_id'=>$restaurantId,'meal_times'=>1,
        'start_time'=>$day,'end_time'=>$day];
    $json=cdxCfPost($base,'/p/restaurant/richness',$baseForm);
    $data=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($data)
        || ($data['datex']??null)!==[$day]
        || (int)($data['table']['sum'][0]??-1)!==1) {
        throw new RuntimeException('Formal Restaurant richness synthetic count mismatch');
    }
    $result['events'][]=['route'=>'/p/restaurant/richness','code'=>0,
        'category_one_sum'=>1,'data_types'=>array_map('gettype',$data)];
    $json=cdxCfPost($base,'/p/restaurant/foodStructure',$baseForm);
    $data=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($data)
        || !cdxCfContainsName($data,$dishName)
        || array_sum(array_map('intval',(array)($data['sum']??[])))!==1) {
        throw new RuntimeException('Formal Restaurant foodStructure synthetic mismatch');
    }
    $result['events'][]=['route'=>'/p/restaurant/foodStructure','code'=>0,
        'own_dish_present'=>true,'sum_total'=>1,
        'data_types'=>array_map('gettype',$data)];
    $json=cdxCfPost($base,'/p/restaurant/nutrition',
        array_replace($baseForm,['status'=>1]));
    $data=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($data)
        || !cdxCfContainsName($data,$dishName)) {
        throw new RuntimeException('Formal Restaurant nutrition own dish missing');
    }
    $result['events'][]=['route'=>'/p/restaurant/nutrition','code'=>0,
        'own_dish_present'=>true,'data_root_type'=>gettype($data)];
    $json=cdxCfPost($base,'/p/restaurant/daypopularity',
        ['restaurant_id'=>$restaurantId,'menu_date'=>$day,'meal_times'=>1]);
    $data=$json['data']??null;
    if (($json['code']??null)!==0 || !is_array($data)
        || !in_array($dishName,(array)($data['x']??[]),true)) {
        throw new RuntimeException('Formal Restaurant daypopularity own dish missing');
    }
    $result['events'][]=['route'=>'/p/restaurant/daypopularity','code'=>0,
        'own_dish_present'=>true,'data_types'=>array_map('gettype',$data)];
    $json=cdxCfPost($base,'/p/restaurant/morepopularity',$baseForm);
    $data=$json['data']??null;
    $own=cdxCfFindRow((array)($data['table']??[]),$dishName);
    if (($json['code']??null)!==0 || !is_array($data)
        || $own===null || (float)($own['popularity']??-1)<=0) {
        throw new RuntimeException('Formal Restaurant morepopularity own dish missing');
    }
    $result['events'][]=['route'=>'/p/restaurant/morepopularity',
        'code'=>0,'own_dish_present'=>true,
        'own_row_types'=>array_map('gettype',$own)];
} catch (Throwable $error) {
    $result['failure']=['phase'=>$phase,'class'=>get_class($error),
        'code'=>$error->getCode()];
} finally {
    try {
        $cleanup=$open();
        $targets=[
            ['date_menu','UUID',$dateMenuUuid,' AND DISHES_UUID=? AND STAFF_UUID=? AND CREATE_BY=?',
                [$dishUuid,$fakeStaffUuid,$marker]],
            ['recipes','UUID',$recipeUuid,
                ' AND DISHES_UUID=? AND MENU_DATE=? AND CREATE_BY=?',
                [$dishUuid,$day,$marker]],
            ['dish','UUID',$componentUuid,
                ' AND DISHES_UUID=? AND COMPOSITION_ID=? AND COMPOSITION_NAME=?'
                .' AND CREATE_BY=?',
                [$dishUuid,$foodId,$foodName,$marker]],
        ];
        foreach ($targets as $target) {
            [$key,$column,$id,$extra,$extraArgs]=$target;
            $count=cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables[$key]
                .' WHERE '.$column.'=?',[$id]);
            if ($count>1) throw new RuntimeException('Synthetic child cardinality unsafe');
            if ($count===1) {
                $stmt=$cleanup->prepare('DELETE FROM '.$tables[$key]
                    .' WHERE '.$column.'=?'.$extra);
                $stmt->execute(array_merge([$id],$extraArgs));
                if ($stmt->rowCount()!==1) {
                    throw new RuntimeException('Synthetic child exact delete failed');
                }
                $result['cleanup'][$key.'_deleted']=1;
            }
        }
        if (cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['dish']
            .' WHERE DISHES_UUID=?',[$dishUuid])!==0
            || cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['recipes']
                .' WHERE DISHES_UUID=?',[$dishUuid])!==0
            || cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['date_menu']
                .' WHERE DISHES_UUID=?',[$dishUuid])!==0) {
            throw new RuntimeException('Dish has unexpected relations; refuse parent delete');
        }
        if ($dishId<=0) {
            $found=cdxCfRows($cleanup,'SELECT ID FROM '.$tables['dishes']
                .' WHERE UUID=? AND NAME=? AND CREATE_BY=?',
                [$dishUuid,$dishName,$marker]);
            if (count($found)>1) throw new RuntimeException('Dish cardinality unsafe');
            $dishId=$found?(int)$found[0]['id']:0;
        }
        if ($dishId>0) {
            $stmt=$cleanup->prepare('DELETE FROM '.$tables['dishes']
                .' WHERE ID=? AND UUID=? AND NAME=? AND CREATE_BY=? AND STORE_ID=10001');
            $stmt->execute([$dishId,$dishUuid,$dishName,$marker]);
            if ($stmt->rowCount()!==1) throw new RuntimeException('Dish exact delete failed');
            $result['cleanup']['dishes_deleted']=1;
        }
        if ($foodId<=0) {
            $found=cdxCfRows($cleanup,'SELECT ID FROM '.$tables['foods_composition']
                .' WHERE NAME=? AND CREATE_BY=? AND STORE_ID=10001',
                [$foodName,$marker]);
            if (count($found)>1) throw new RuntimeException('Food cardinality unsafe');
            $foodId=$found?(int)$found[0]['id']:0;
        }
        if ($foodId>0) {
            if (cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['dish']
                .' WHERE COMPOSITION_ID=?',[$foodId])!==0) {
                throw new RuntimeException('Food has unexpected dish references');
            }
            $stmt=$cleanup->prepare('DELETE FROM '.$tables['foods_composition']
                .' WHERE ID=? AND NAME=? AND CREATE_BY=? AND STORE_ID=10001');
            $stmt->execute([$foodId,$foodName,$marker]);
            if ($stmt->rowCount()!==1) throw new RuntimeException('Food exact delete failed');
            $result['cleanup']['food_deleted']=1;
        }
        $links=cdxCfRows($cleanup,'SELECT ID,MENU_UUID,CREATE_BY FROM '
            .$tables['role_menu'].' WHERE ROLE_UUID=?',[$roleUuid]);
        if (count($links)>count($menuUuids)) {
            throw new RuntimeException('Role-menu cardinality unsafe');
        }
        foreach ($links as $link) {
            if (!in_array((string)$link['menu_uuid'],$menuUuids,true)
                || (string)$link['create_by']!==$marker) {
                throw new RuntimeException('Unexpected role-menu link');
            }
            $stmt=$cleanup->prepare('DELETE FROM '.$tables['role_menu']
                .' WHERE ID=? AND ROLE_UUID=? AND MENU_UUID=? AND CREATE_BY=?');
            $stmt->execute([(int)$link['id'],$roleUuid,
                (string)$link['menu_uuid'],$marker]);
            if ($stmt->rowCount()!==1) throw new RuntimeException('Role-menu exact delete failed');
            $result['cleanup']['role_menu_deleted']=
                ($result['cleanup']['role_menu_deleted']??0)+1;
        }
        if (cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['user_role']
            .' WHERE ROLE_UUID=? AND USER_UUID<>?',[$roleUuid,$userUuid])!==0) {
            throw new RuntimeException('Other user linked to synthetic role');
        }
        $stmt=$cleanup->prepare('DELETE FROM '.$tables['user_role']
            .' WHERE USER_UUID=? AND ROLE_UUID=? AND CREATE_BY=?');
        $stmt->execute([$userUuid,$roleUuid,$marker]);
        $result['cleanup']['user_role_deleted']=$stmt->rowCount();
        if ($roleId<=0) {
            $found=cdxCfRows($cleanup,'SELECT ID FROM '.$tables['role']
                .' WHERE UUID=? AND NAME=? AND CREATE_BY=?',
                [$roleUuid,$marker,'CODEX']);
            if (count($found)>1) throw new RuntimeException('Role cardinality unsafe');
            $roleId=$found?(int)$found[0]['id']:0;
        }
        if ($userId<=0) {
            $found=cdxCfRows($cleanup,'SELECT ID FROM '.$tables['user']
                .' WHERE UUID=? AND ACCOUNT=? AND TYPE=1',[$userUuid,$marker]);
            if (count($found)>1) throw new RuntimeException('User cardinality unsafe');
            $userId=$found?(int)$found[0]['id']:0;
        }
        if ($roleId>0) {
            $stmt=$cleanup->prepare('DELETE FROM '.$tables['role']
                .' WHERE ID=? AND UUID=? AND NAME=? AND CREATE_BY=?');
            $stmt->execute([$roleId,$roleUuid,$marker,'CODEX']);
            if ($stmt->rowCount()!==1) throw new RuntimeException('Role exact delete failed');
            $result['cleanup']['role_deleted']=1;
        }
        if ($userId>0) {
            $stmt=$cleanup->prepare('DELETE FROM '.$tables['user']
                .' WHERE ID=? AND UUID=? AND ACCOUNT=? AND TYPE=1');
            $stmt->execute([$userId,$userUuid,$marker]);
            if ($stmt->rowCount()!==1) throw new RuntimeException('User exact delete failed');
            $result['cleanup']['user_deleted']=1;
        }
        $zero=[
            ['foods_composition','NAME',$foodName],['dishes','UUID',$dishUuid],
            ['dish','UUID',$componentUuid],['recipes','UUID',$recipeUuid],
            ['date_menu','UUID',$dateMenuUuid],['user','ACCOUNT',$marker],
            ['role','NAME',$marker],
        ];
        foreach ($zero as $check) {
            $result['cleanup'][$check[0].'_zero']=cdxCfCount($cleanup,
                'SELECT COUNT(*) N FROM '.$tables[$check[0]]
                .' WHERE '.$check[1].'=?',[$check[2]])===0;
        }
        $result['cleanup']['historical_day_zero']=
            cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['recipes']
                .' WHERE MENU_DATE=? AND RESTAURANT_ID=?',
                [$day,$restaurantId])===0
            && cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '.$tables['date_menu']
                .' WHERE MENU_DATE=? AND RESTAURANT_ID=?',
                [$day,$restaurantId])===0;
        $result['cleanup']['links_zero']=cdxCfCount($cleanup,
            'SELECT COUNT(*) N FROM '.$tables['role_menu']
            .' WHERE ROLE_UUID=?',[$roleUuid])===0
            && cdxCfCount($cleanup,'SELECT COUNT(*) N FROM '
                .$tables['user_role'].' WHERE USER_UUID=? AND ROLE_UUID=?',
                [$userUuid,$roleUuid])===0;
    } catch (Throwable $error) {
        $result['cleanup_error']=['class'=>get_class($error),
            'code'=>$error->getCode()];
    }
}
echo json_encode($result,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT).PHP_EOL;
if (isset($result['failure']) || isset($result['cleanup_error'])) exit(1);
foreach ($result['cleanup'] as $key=>$value) {
    if (substr($key,-5)==='_zero' && $value!==true) exit(1);
}
