<?php
declare(strict_types=1);
date_default_timezone_set('Asia/Shanghai');
$lane=(string)getenv('CATEGORY_LANE');$base=(string)getenv('CATEGORY_BASE');$runtime=(string)getenv('CATEGORY_RUNTIME');
if(!in_array($lane,['B','C'],true)||!preg_match('#^http://127\.0\.0\.1:1826[12]$#D',$base))exit(78);
$dm=getenv('POC_DIALECT')==='dm';
$connect=static function()use($dm):PDO{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]);};
$db=$connect();
$assert=static function(bool $ok,string $reason):void{if(!$ok)throw new RuntimeException($reason);};
if($dm)$assert($db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn()==='AIZHCT_APP','DM identity');
else $assert(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);return $s->fetchAll(PDO::FETCH_ASSOC);};
$prefix='CDXGS10E9F3';
$own=static function()use($query,$prefix):array{return $query('SELECT * FROM yoshop_goods_service WHERE name LIKE ? AND store_id=10001 ORDER BY service_id',[$prefix.'%']);};
if(($argv[1]??'')==='audit'){echo json_encode(['lane'=>$lane,'owned_rows'=>count($own())]),"\n";exit(count($own())?1:0);}
$assert(!$own(),'Fixture prefix already exists');
$metadata=$dm?$query("SELECT COLUMN_NAME FROM USER_TAB_COLUMNS WHERE TABLE_NAME='YOSHOP_GOODS_SERVICE'")
    :$query("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='yoshop_goods_service'");
$columnNames=array_map(static function(array $row):string{return strtolower($row['column_name']);},$metadata);sort($columnNames);
$expectedColumns=['service_id','name','summary','is_default','status','sort','is_delete','store_id','create_time','update_time'];sort($expectedColumns);
$assert($columnNames===$expectedColumns,'Formal schema columns drift');
$triggers=$dm?$query("SELECT COUNT(*) n FROM USER_TRIGGERS WHERE TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL')")
    :$query("SELECT COUNT(*) n FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE IN ('yoshop_goods_service','yoshop_goods_service_rel')");
$fks=$dm?$query("SELECT COUNT(*) n FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R' AND (TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL') OR R_CONSTRAINT_NAME IN (SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME IN ('YOSHOP_GOODS_SERVICE','YOSHOP_GOODS_SERVICE_REL')))")
    :$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 ('yoshop_goods_service','yoshop_goods_service_rel') OR REFERENCED_TABLE_NAME IN ('yoshop_goods_service','yoshop_goods_service_rel'))");
$assert((int)$triggers[0]['n']===0&&(int)$fks[0]['n']===0,'Trigger/FK side effect gate');
$snapshot=static function()use($query):array{$result=[];foreach(['goods_service'=>'service_id','goods_service_rel'=>'id'] as $table=>$pk){
    $rows=$query('SELECT * FROM yoshop_'.$table.' ORDER BY '.$pk);$result[$table]=['rows'=>count($rows),'sha'=>hash('sha256',json_encode($rows))];}return $result;};
$before=$snapshot();
$boundary=json_decode((string)file_get_contents($base.'/__poc_boundary'),true);
$assert(!empty($boundary['external_stubs'])&&!empty($boundary['private_cache'])&&$boundary['allowlist']==='goods-service-only','Private boundary');
$root=(string)getenv('CATEGORY_ROOT');define('TP_ENV','poc');define('BUSINESS','aizhct');define('ENTERPRISE_NO','10001');require $root.'/vendor/autoload.php';
$app=new \think\App($root);$app->setEnvName('poc');$app->setRuntimePath($runtime.'/fixture-runtime/');$app->initialize();
$cache=new \think\cache\driver\File($app,['path'=>$runtime.'/cache/','prefix'=>'','expire'=>0]);
$token=bin2hex(random_bytes(24));$cache->set($token,['user'=>['store_user_id'=>2147000061,'store_id'=>10001,
    'real_name'=>$prefix,'user_name'=>$prefix,'is_super'=>1],'store_id'=>10001,'is_login'=>true],1800);
$cases=[];$ids=[];$error=null;$privateResponses=[];
file_put_contents($runtime.'/queries.jsonl','');chmod($runtime.'/queries.jsonl',0600);
$request=static function(string $module,string $scenario,string $action,array $args=[],array $form=[],string $encoding='json')use($base,$token,&$privateResponses):array{
    $method=in_array($action,['list','all'],true)?'GET':'POST';$scenario='PILOT_GS_'.strtoupper($module).'_'.$scenario;
    $url=$base.'/'.$module.'/goods.Service/'.$action.($args?'?'.http_build_query($args):'');
    $header="Access-Token: ".$token."\r\nPlatform: POC\r\nX-Pilot-Scenario: ".$scenario."\r\nContent-Type: ".($encoding==='json'?'application/json':'application/x-www-form-urlencoded')."\r\n";
    $content=$encoding==='json'?json_encode(['form'=>$form],JSON_UNESCAPED_UNICODE):http_build_query(['form'=>$form]);
    $raw=file_get_contents($url,false,stream_context_create(['http'=>['method'=>$method,'header'=>$header,'content'=>$content,'timeout'=>30,'ignore_errors'=>true]]));
    preg_match('#^HTTP/\S+\s+(\d+)#',$http_response_header[0]??'',$match);$body=json_decode((string)$raw,true);
    if(!is_array($body))throw new RuntimeException('Non JSON '.$scenario);
    $privateResponses[$scenario]=['http_status'=>(int)($match[1]??0),'body'=>$body];
    return ['scenario'=>$scenario,'method'=>$method,'path'=>'/'.$module.'/goods.Service/'.$action,'encoding'=>$encoding,
        'http_status'=>(int)($match[1]??0),'body'=>$body];
};
$expectSuccess=static function(array $case)use($assert):void{$assert($case['http_status']===200&&($case['body']['status']??null)===200,'Business failure '.$case['scenario']);};
$read=static function(string $module,string $scenario,string $action,int $expectedRows,int $page=1)use($request,$expectSuccess,$assert,$query,$prefix,&$cases):void{
    $case=$request($module,$scenario,$action,['search'=>$prefix.'_'.$module,'page'=>$page]);$expectSuccess($case);
    $rows=$query('SELECT * FROM yoshop_goods_service WHERE name LIKE ? AND store_id=10001 AND is_delete=0 ORDER BY sort,service_id',[$prefix.'_'.$module.'%']);
    $list=$action==='list'?($case['body']['data']['list']['data']??null):($case['body']['data']['list']??null);
    $assert(is_array($list)&&count($list)===$expectedRows,'Read row count '.$scenario);
    $expected=$page>1?[]:$rows;$assert(count($list)===count($expected),'Read/source cardinality');
    if($action==='list')$assert(($case['body']['data']['list']['total']??-1)===count($rows),'Paginator source total');
    foreach($list as $index=>&$row){$source=$expected[$index];
        foreach($source as $key=>$value){
            $assert(array_key_exists($key,$row),'Missing source field');
            if(in_array($key,['create_time','update_time'],true)){
                $assert($row[$key]===date('Y-m-d H:i:s',(int)$value),'Timestamp/source mismatch');
                if($key==='update_time')$row[$key]='INDEPENDENTLY_VERIFIED_UPDATE_TIME';
            }elseif(is_numeric($value))$assert(is_int($row[$key])&&$row[$key]===(int)$value,'Integer/source mismatch');
            else $assert($row[$key]===$value,'Text/source mismatch');
        }
    }unset($row);
    if($action==='list')$case['body']['data']['list']['data']=$list;else $case['body']['data']['list']=$list;
    $case['independent_source_rows']=count($rows);$case['returned_rows']=$expectedRows;$case['all_source_fields_equal']=true;$cases[]=$case;
};
try{
foreach(['store','terminal'] as $module){
    $read($module,'EMPTY_FILTER','list',0);
    $name=$prefix.'_'.$module.'_餐牌\'承诺\\';$summary='中文服务\'反斜杠\\';
    $form=['name'=>$name,'summary'=>$summary,'status'=>0,'is_default'=>0,'sort'=>2147000061,
        'create_time'=>1609459200,'update_time'=>1609459200];
    $case=$request($module,'ADD','add',[],$form);$expectSuccess($case);
    $rows=$query('SELECT * FROM yoshop_goods_service WHERE name=? AND store_id=10001 ORDER BY service_id',[$name]);
    $assert(count($rows)===1&&$rows[0]['summary']===$summary&&(int)$rows[0]['status']===0&&(int)$rows[0]['is_default']===0,'Add original state');
    $firstId=(int)$rows[0]['service_id'];$ids[$firstId]=1;$case['independent_state']=['rows'=>1,'summary_equal'=>true,'status'=>0,'is_default'=>0];$cases[]=$case;
    $case=$request($module,'DUPLICATE_ADD','add',[],$form,'form');$expectSuccess($case);
    $rows=$query('SELECT * FROM yoshop_goods_service WHERE name=? AND store_id=10001 ORDER BY service_id',[$name]);
    $assert(count($rows)===2&&(int)$rows[1]['service_id']!==$firstId,'Duplicate original semantics');
    $secondId=(int)$rows[1]['service_id'];$ids[$secondId]=2;$case['independent_state']=['rows'=>2,'distinct_primary_keys'=>true,'duplicate_name_allowed'=>true];$cases[]=$case;
    $read($module,'ALL_ADDED','all',2);$read($module,'LIST_ADDED','list',2);
    $emptySummary=$form;$emptySummary['summary']='';$emptySummary['sort']=2147000063;
    $case=$request($module,'EDIT_FORM_EMPTY_SUMMARY','edit',['serviceId'=>$firstId],$emptySummary,'form');$expectSuccess($case);
    $rows=$query('SELECT * FROM yoshop_goods_service WHERE service_id=?',[$firstId]);
    $assert(count($rows)===1&&$rows[0]['summary']===''&&(int)$rows[0]['sort']===2147000063,'Empty summary original state');
    $case['independent_state']=['rows'=>1,'summary_is_empty_string'=>true,'sort'=>2147000063];$cases[]=$case;
    $edited=$form;$edited['name']=$prefix.'_'.$module.'_修改';$edited['summary']='修改\'中文\\';$edited['sort']=2147000062;
    $case=$request($module,'EDIT_JSON','edit',['serviceId'=>$secondId],$edited);$expectSuccess($case);
    $rows=$query('SELECT * FROM yoshop_goods_service WHERE service_id=?',[$secondId]);
    $assert(count($rows)===1&&$rows[0]['name']===$edited['name']&&$rows[0]['summary']===$edited['summary']&&(int)$rows[0]['sort']===2147000062,'Edit original state');
    $case['independent_state']=['rows'=>1,'name_summary_equal'=>true,'sort'=>2147000062];$cases[]=$case;
    $read($module,'ALL_EDITED','all',2);$read($module,'PAGE_TWO','list',0,2);
    foreach([['DELETE_FIRST',$firstId],['REPEAT_DELETE',$firstId]] as $delete){
        $case=$request($module,$delete[0],'delete',['serviceId'=>$delete[1]]);$expectSuccess($case);
        $rows=$query('SELECT is_delete FROM yoshop_goods_service WHERE service_id=?',[$delete[1]]);
        $assert(count($rows)===1&&(int)$rows[0]['is_delete']===1,'Soft delete original state');
        $case['independent_state']=['physical_rows'=>1,'is_delete'=>1,'soft_delete_only'=>true];$cases[]=$case;
    }
    $read($module,'ALL_ONE','all',1);
    $case=$request($module,'DELETE_SECOND','delete',['serviceId'=>$secondId]);$expectSuccess($case);
    $rows=$query('SELECT is_delete FROM yoshop_goods_service WHERE service_id=?',[$secondId]);
    $assert(count($rows)===1&&(int)$rows[0]['is_delete']===1,'Second soft delete state');
    $case['independent_state']=['physical_rows'=>1,'is_delete'=>1,'soft_delete_only'=>true];$cases[]=$case;
    $read($module,'ALL_EMPTY','all',0);$read($module,'LIST_EMPTY','list',0);
}
}catch(Throwable $caught){$error=['class'=>get_class($caught),'message'=>$caught->getMessage(),'line'=>$caught->getLine()];}
finally{
    foreach($own() as $row){$s=$db->prepare('DELETE FROM yoshop_goods_service WHERE service_id=? AND name LIKE ? AND store_id=10001');$s->execute([$row['service_id'],$prefix.'%']);}
    $cache->delete($token);
}
$fresh=$connect();$s=$fresh->prepare('SELECT COUNT(*) FROM yoshop_goods_service WHERE name LIKE ? AND store_id=10001');$s->execute([$prefix.'%']);$remaining=(int)$s->fetchColumn();
$relations=0;foreach(array_keys($ids) as $id){$s=$fresh->prepare('SELECT COUNT(*) FROM yoshop_goods_service_rel WHERE service_id=?');$s->execute([$id]);$relations+=(int)$s->fetchColumn();}
$cleanup=['fresh_pdo_owned_rows'=>$remaining,'owned_relation_rows'=>$relations,'token_absent'=>$cache->get($token)===null,'natural_tables_unchanged'=>$snapshot()===$before];
$normalise=static function($value)use(&$normalise,$ids){if(!is_array($value))return $value;foreach($value as $key=>&$part){
    if($key==='service_id'&&is_int($part)&&isset($ids[$part]))$part=$ids[$part];else $part=$normalise($part);
}unset($part);return $value;};
foreach($cases as &$case){$trace=$case['body']['trace_id']??null;$case['trace_format_valid']=is_string($trace)&&preg_match('/^[0-9a-f]{13}$/D',$trace)===1;
    if($case['trace_format_valid'])$case['body']['trace_id']='VALID_DYNAMIC_TRACE';$case=$normalise($case);}unset($case);
$events=[];foreach(file($runtime.'/queries.jsonl',FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES)?:[] as $line)$events[]=json_decode($line,true);
$report=['lane'=>$lane,'boundary_verified'=>true,'metadata'=>['formal_columns_equal'=>true,'triggers'=>0,'foreign_keys'=>0],
    'case_count'=>count($cases),'cases'=>$cases,'cleanup'=>$cleanup,'source_before'=>$before,'error'=>$error,'events'=>$events,
    'normalization'=>'validated trace; independently read service_id integers; own update_time string verified field-by-field against original DB',
    'limitations'=>'No nonzero goods relation refusal, unknown IDs, full invalid-type/length matrix, outage/concurrency or performance; duplicate name is original allowed behavior'];
file_put_contents($runtime.'/report.json',json_encode($report,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE));chmod($runtime.'/report.json',0600);
file_put_contents($runtime.'/private-responses.json',json_encode($privateResponses,JSON_UNESCAPED_UNICODE));chmod($runtime.'/private-responses.json',0600);
echo json_encode(['lane'=>$lane,'cases'=>count($cases),'cleanup'=>$cleanup,'error'=>$error,'report'=>$runtime.'/report.json']),"\n";
exit($error!==null||$remaining!==0||$relations!==0||in_array(false,$cleanup,true)?1:0);
