<?php
declare(strict_types=1);
$lane=getenv('MR3_LANE');$root=getenv('MR3_ROOT');$cfg=(static function($f){return require $f;})($root.'/application/database.php');
if($lane==='B'){$local=(static function($f){return require $f;})('/workspace/zhct/zhctproject/store/application/config/local/database.php');foreach(['hostname','database','username','password']as $k)if($cfg[$k]!==$local[$k])throw new RuntimeException('Not code local');$dsn='mysql:host='.$cfg['hostname'].';port='.($cfg['hostport']?:3306).';dbname='.$cfg['database'].';charset=utf8mb4';}else{if($cfg['hostname']!=='127.0.0.1'||(string)$cfg['hostport']!=='5237'||$cfg['database']!=='ZHCT_APP')throw new RuntimeException('DM scope');$dsn='dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';}
$db=new PDO($dsn,$cfg['username'],$cfg['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER]);$p=$lane==='B'?'ydy_':'YDY_';
$q=static function(string $sql,array $args=[])use($db):array{$s=$db->prepare($sql);$s->execute($args);$rows=[];while($r=$s->fetch(PDO::FETCH_ASSOC)){$r=array_change_key_case($r,CASE_LOWER);foreach($r as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);$rows[]=$r;if(count($rows)>10000)throw new RuntimeException('Bounded result cap');}return $rows;};
$hashRows=static function(string $sql,array $args=[])use($db):array{$s=$db->prepare($sql);$s->execute($args);$ctx=hash_init('sha256');$n=0;while($r=$s->fetch(PDO::FETCH_ASSOC)){$r=array_change_key_case($r,CASE_LOWER);foreach($r as &$v)if(is_resource($v))$v=stream_get_contents($v);unset($v);hash_update($ctx,serialize($r));if(++$n>100000)throw new RuntimeException('Bounded source cap');}return ['rows'=>$n,'sha256'=>hash_final($ctx)];};
$check=static function(bool $ok,string $why):void{if(!$ok)throw new RuntimeException($why);};$report=['lane'=>$lane,'business_dml'=>0,'ddl'=>0,'safe'=>false,'failure'=>null];
try{
 if($lane==='B')$check(strpos((string)$db->query('SELECT VERSION()')->fetchColumn(),'5.6.')===0,'MySQL 5.6');else $check($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()==='ZHCT_APP','DM identity');
 $table=$p.'dishes_custom_category';$report['columns']=$lane==='B'?$q('SELECT COLUMN_NAME,COLUMN_TYPE,IS_NULLABLE,COLUMN_DEFAULT,EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY ORDINAL_POSITION',[$table]):$q('SELECT COLUMN_NAME,DATA_TYPE,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',[strtoupper($table)]);
 $check(count($report['columns'])>=9,'Required table columns');$names=array_map('strtolower',array_column($report['columns'],'column_name'));foreach(['id','code','name','status','is_system','is_delete','create_by','create_time','update_time']as $key)$check(in_array($key,$names,true),'Missing required column');
 $report['indexes']=$lane==='B'?$q('SELECT INDEX_NAME,NON_UNIQUE,SEQ_IN_INDEX,COLUMN_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY INDEX_NAME,SEQ_IN_INDEX',[$table]):$q('SELECT I.INDEX_NAME,I.UNIQUENESS,C.COLUMN_POSITION,C.COLUMN_NAME 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($table)]);
 $report['triggers']=$lane==='B'?$q('SELECT TRIGGER_NAME,EVENT_MANIPULATION FROM information_schema.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=?',[$table]):$q('SELECT TRIGGER_NAME,STATUS,TRIGGERING_EVENT FROM USER_TRIGGERS WHERE TABLE_NAME=?',[strtoupper($table)]);$check($report['triggers']===[],'Unknown trigger');
 $report['constraints']=$lane==='B'?$q('SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[$table]):$q('SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,STATUS FROM USER_CONSTRAINTS WHERE TABLE_NAME=? ORDER BY CONSTRAINT_NAME',[strtoupper($table)]);
 $report['category_source']=$hashRows('SELECT * FROM '.$table.' ORDER BY ID');$report['dishes_source']=$hashRows('SELECT ID,UUID,CUSTOM_CATEGORY_ID,IS_DELETE,IS_DEL FROM '.$p.'dishes ORDER BY ID');
 $check($q('SELECT ID FROM '.$table.' WHERE CODE=? AND IS_SYSTEM=1 AND IS_DELETE=0',['other'])!==[],'System classification exists');$report['original_debug']=$cfg['debug']??null;$report['safe']=true;
}catch(Throwable $e){$report['failure']=['class'=>get_class($e),'reason'=>$e->getMessage()];}
if(!defined('CDX_CATEGORY_CONTEXT')){file_put_contents(__DIR__.'/private-preflight.json',json_encode($report,JSON_PRETTY_PRINT));chmod(__DIR__.'/private-preflight.json',0600);echo json_encode($report),"\n";exit($report['safe']?0:2);}
if(!$report['safe'])throw new RuntimeException('Category preflight unsafe');
