<?php
declare(strict_types=1);
date_default_timezone_set('Asia/Shanghai');
$lane=(string)getenv('CATEGORY_LANE');$runtime=(string)getenv('CATEGORY_RUNTIME');$base=(string)getenv('CATEGORY_BASE');
$check=static function(bool $ok,string $reason):void{if(!$ok)throw new RuntimeException($reason);};
$check(in_array($lane,['B','C'],true)&&preg_match('#^http://127\.0\.0\.1:1832[12]$#D',$base)===1,'Private lane');
$dm=getenv('POC_DIALECT')==='dm';$tenant=2147000621;$marker='CDXSP10F6A1';
$tables=['user','staff','habit','user_weight_status','nurtition_target','meal_recommend','meal_recommend_history'];
$pk=['user'=>'user_id'];
$connect=static function()use($dm):PDO{try{return new PDO($dm?'dm:host=127.0.0.1;port=5238;schema=AIZHCT_APP':
    'mysql:host='.getenv('POC_AI_HOST').';port='.getenv('POC_AI_PORT').';dbname='.getenv('POC_AI_SCHEMA').';charset=utf8',
    getenv('POC_AI_USER'),getenv('POC_AI_PASSWORD'),[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER]);
}catch(Throwable $e){throw new RuntimeException('Database connection preflight failed');}};
$db=$connect();
if($dm)$check($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()==='AIZHCT_APP','DM identity');
else $check(strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')===0&&$db->query('SELECT DATABASE()')->fetchColumn()===getenv('POC_AI_SCHEMA'),'Local MySQL identity');
$query=static function(string $sql,array $args=[])use($db):array{$s=$db->prepare($sql);$s->execute($args);$rows=$s->fetchAll(PDO::FETCH_ASSOC);
    foreach($rows as &$row)foreach($row as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($row,$v);return $rows;};
$counts=static function()use($query,$tables,$tenant):array{$out=[];foreach($tables as $table)$out[$table]=(int)$query('SELECT COUNT(*) n FROM yoshop_'.$table.' WHERE store_id=?',[$tenant])[0]['n'];return $out;};
$metadata=[];
$cached=__DIR__.'/structure-'.$lane.'.json';
if(($argv[1]??'')!=='preflight'&&is_file($cached)){
    $gate=json_decode((string)file_get_contents($cached),true);
    $check(($gate['lane']??'')===$lane&&($gate['dml']??null)===0&&($gate['foreign_keys']??null)===0&&($gate['triggers']??null)===0,'Cached live metadata gate');
    $metadata=$gate['metadata'];$fk=0;$trigger=0;
}else{
foreach($tables as $table){$name='yoshop_'.$table;
    $columns=$dm?$query('SELECT COLUMN_NAME,DATA_TYPE,NULLABLE,DATA_DEFAULT,DATA_LENGTH,DATA_PRECISION,DATA_SCALE FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[strtoupper($name)])
        :$query('SELECT COLUMN_NAME,DATA_TYPE,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,CHARACTER_MAXIMUM_LENGTH,NUMERIC_PRECISION,NUMERIC_SCALE,EXTRA FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',[$name]);
    $check(count($columns)>0,'Missing table '.$table);
    $indexes=$dm?$query('SELECT i.INDEX_NAME,i.UNIQUENESS,c.COLUMN_NAME,c.COLUMN_POSITION FROM USER_INDEXES i JOIN USER_IND_COLUMNS c ON i.INDEX_NAME=c.INDEX_NAME WHERE i.TABLE_NAME=? ORDER BY i.INDEX_NAME,c.COLUMN_POSITION',[strtoupper($name)])
        :$query('SELECT INDEX_NAME,NON_UNIQUE,COLUMN_NAME,SEQ_IN_INDEX FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',[$name]);
    $metadata[$table]=['columns'=>$columns,'indexes'=>$indexes];
}
$list=implode(',',array_map(static function(string $t)use($dm):string{return "'".($dm?strtoupper('yoshop_'.$t):'yoshop_'.$t)."'";},$tables));
$trigger=(int)($dm?$query('SELECT COUNT(*) n FROM USER_TRIGGERS WHERE TABLE_NAME IN ('.$list.')'):$query('SELECT COUNT(*) n FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE IN ('.$list.')'))[0]['n'];
$fk=(int)($dm?$query("SELECT COUNT(*) n FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R' AND (TABLE_NAME IN (".$list.') OR R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME IN ('.$list.')))'):
    $query('SELECT COUNT(*) n FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA=DATABASE() AND REFERENCED_TABLE_NAME IS NOT NULL AND (TABLE_NAME IN ('.$list.') OR REFERENCED_TABLE_NAME IN ('.$list.'))'))[0]['n'];
$check($fk===0&&$trigger===0,'FK/trigger side effect');
}
$scanMetrics=[];
$snapshot=static function()use($connect,$tables,$pk,$dm,&$scanMetrics):array{$scan=$connect();if(!$dm)$scan->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,false);$out=[];$metrics=[];
    foreach(array_merge(array_diff($tables,['meal_recommend','meal_recommend_history']),['config_enum','general_vm']) as $table){$start=microtime(true);$s=$scan->query('SELECT * FROM yoshop_'.$table.' ORDER BY '.($pk[$table]??'id'));$hash=hash_init('sha256');$count=0;
        while($row=$s->fetch(PDO::FETCH_ASSOC)){foreach($row as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);hash_update($hash,serialize($row));++$count;}$s->closeCursor();
        $out[$table]=['rows'=>$count,'sha256'=>hash_final($hash)];$metrics[$table]=['rows'=>$count,'elapsed_ms'=>(int)round((microtime(true)-$start)*1000)];}
    $scanMetrics[]=$metrics;return $out;};
