<?php
declare(strict_types=1);
final class CoreGate{
 public static $scenario='';public static $ids=[];public static $started=0;public static $meta=false;public static $total=0;public static $counts=[];public static $generated=[];public static $last=[];public static $metadataMap=null;
 public static $dataTables=['AI'=>['store','store_setting','upload_file','user','user_oauth','user_weight'],'ZHCT'=>['user']];
 const COLUMNS='SELECT COLUMN_NAME,DATA_TYPE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID';
 const PRIMARY="SELECT cc.COLUMN_NAME FROM USER_CONSTRAINTS c JOIN USER_CONS_COLUMNS cc ON c.CONSTRAINT_NAME=cc.CONSTRAINT_NAME WHERE c.TABLE_NAME=? AND c.CONSTRAINT_TYPE='P'";
 public static function rec($r){$r['scenario']=self::$scenario;event('business-native.jsonl',$r);}
 public static function known($db,$table){global $runtime;if(self::$metadataMap===null)self::$metadataMap=json_decode(file_get_contents($runtime.'/metadata-tables.json'),true);ck(isset(self::$metadataMap[$db])&&self::$metadataMap[$db]['schema']===getenv('POC_'.$db.'_SCHEMA'),'Exact approved metadata schema/current connection');ck(is_string($table)&&preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/D',$table)===1,'Exact nonempty unqualified metadata table name');$name=strtolower($table);ck(strpos($name,$db==='AI'?'yoshop_':'ydy_')===0&&in_array($name,self::$metadataMap[$db]['tables'],true),'Frozen existing same-schema metadata table');}
 public static function kind($db,$sql){$plain=preg_replace("/'(?:''|\\\\.|[^'\\\\])*'/s",'?', $sql);ck(!preg_match('/;|--|\/\*|\*\/|#|\b(?:INSERT|UPDATE|DELETE|REPLACE|MERGE|CREATE|ALTER|DROP|TRUNCATE|GRANT|REVOKE|OUTFILE|DUMPFILE|LOAD|EXEC|EXECUTE|SLEEP|BENCHMARK|UTL_HTTP|NEXTVAL)\b/i',$plain),'Readonly0DMLDDL');
  if($sql===self::COLUMNS||$sql===self::PRIMARY)return 'metadata_SELECT';
  if(preg_match('/^SHOW FULL COLUMNS FROM `([A-Za-z_][A-Za-z0-9_]*)`$/D',$sql,$m)){self::known($db,$m[1]);return 'metadata_SHOW';}
  if($sql==='CALL SP_TABLEDEF(?, ?)'&&self::$meta)return 'metadata_CALL';
  ck(!preg_match('/\bUSER_(?:TAB_COLUMNS|CONSTRAINTS|CONS_COLUMNS|TABLES)\b/i',$sql),'Only exact original metadata catalog shapes');
  if(preg_match('/^\s*SELECT\b/i',$sql)){ck(!preg_match('/\bINTO\b/i',$plain),'No SELECT INTO');preg_match_all('/\b(yoshop|ydy)_([a-z0-9_]+)/i',$sql,$m,PREG_SET_ORDER);ck(count($m)>0,'No unscoped data SELECT');foreach($m as $r)ck(($db==='AI'?strtolower($r[1])==='yoshop':strtolower($r[1])==='ydy')&&in_array(strtolower($r[2]),self::$dataTables[$db],true),'Only approved actor-related data table '.$r[0]);return 'SELECT';}
  throw new RuntimeException('Unknown non-read SQL shape');
 }
 public static function plan($db,$sql,$bind){$kind=self::kind($db,$sql);$v=array_values(array_map(static function($x){return is_array($x)?$x[0]:$x;},$bind));
  if($kind==='metadata_SELECT'){ck(count($v)===1,'Exact original metadata single bind');self::known($db,$v[0]);return;}
  if($kind==='metadata_SHOW'){ck($v===[],'Original SHOW has no binds');return;}
  if($kind==='metadata_CALL'){ck(count($v)===2&&is_string($v[0])&&$v[0]!==''&&$v[0]===strtoupper((string)getenv('POC_'.$db.'_SCHEMA')),'Exact original SP_TABLEDEF schema bind');self::known($db,$v[1]);return;}
  if($kind==='SELECT'){$flat=array_map('strval',$v);$actor=(string)(getenv('CORE_LANE')==='B'?44676:1836);if(preg_match('/\b(?:yoshop_user|yoshop_user_oauth|yoshop_user_weight|ydy_user)\b/i',$sql))ck(in_array($actor,$flat,true),'Exact original actor data lease');elseif(preg_match('/\byoshop_store(?:_setting)?\b/i',$sql))ck(in_array('10001',$flat,true),'Exact original tenant configuration lease');elseif(stripos($sql,'yoshop_upload_file')!==false){global $runtime;$pre=json_decode(file_get_contents($runtime.'/preflight-read.json'),true);$ids=[];foreach($pre['user_fullrows'][0] as $key=>$value)if(strpos($key,'avatar')!==false&&is_numeric($value))$ids[]=(string)$value;ck(count(array_intersect($flat,$ids))>0,'Only actual actor-related avatar file');}}
 }
}
