<?php
declare(strict_types=1);

// Isolated Store HTTP consumer only. Does not change AI's fixed department 10000 call.
if (getenv('CDX_STORE_SYNC_RUN') !== '1') {
    echo json_encode(['status'=>'default_deny','db_or_http_calls'=>0]), PHP_EOL;
    exit(78);
}
$lane=(string)getenv('CDX_HK_TARGET');
$actorId=(int)getenv('CDX_HK_ACTOR_ID');
if (!in_array($lane,['B','C'],true) || $actorId<=0) exit(78);
$root='/tmp/cdx-train-alias-20261012-'.$lane;
$port=$lane==='B'?19121:19122;
$receiptDir=$root.'/runtime';
$pidFile=$root.'/private-http.pid';
$pid=is_file($pidFile)?(int)trim((string)file_get_contents($pidFile)):0;
if ($pid<=1 || !is_file('/proc/'.$pid.'/cmdline')
    || strpos(str_replace("\0",' ',(string)file_get_contents('/proc/'.$pid.'/cmdline')),
        '127.0.0.1:'.$port)===false) exit(78);
$workerEnv=[];
foreach (explode("\0",(string)file_get_contents('/proc/'.$pid.'/environ')) as $item) {
    $pair=explode('=',$item,2);
    if(count($pair)===2 && strpos($pair[0],'POC_')===0) $workerEnv[$pair[0]]=$pair[1];
}
if (($workerEnv['POC_EXTERNAL_STUBS']??null)!=='1'
    || ($workerEnv['POC_REAL_QUEUE']??null)!=='0'
    || ($workerEnv['POC_DIALECT']??null)!==($lane==='B'?'mysql':'dm')) exit(78);
if ($lane==='C') {
    foreach (['POC_HOST'=>'127.0.0.1','POC_PORT'=>'5237',
        'POC_SCHEMA'=>'ZHCT_APP'] as $key=>$expected)
        if (($workerEnv[$key]??null)!==$expected) exit(78);
} else {
    $config=[];
    $local=require '/workspace/zhct/zhctproject/store/application/config/local/database.php';
    foreach (['hostname'=>'HOST','database'=>'SCHEMA','username'=>'USER',
        'password'=>'PASSWORD'] as $from=>$to)
        if((string)($local[$from]??'')!==($workerEnv['POC_'.$to]??null)) exit(78);
}
foreach (['application/api/controller/User.php'=>'b7d1c3bad25d39a3679c8272a0289ea7b99b78110eff8f6dcf123a5910a8f026',
    'application/api/service/User.php'=>'6b46914e474d0838a19a2302ee298328c55103401c5ff18a2b4f909dad95abe2',
    'application/api/service/Department.php'=>'aa31452ba6cb2147a3e0fde493ff04ce886f82f0bf3a4e03237621404a55a8a5',
    'application/p/logic/Department.php'=>'665e4ba4639c1d27448524228ce3ad4568de1700a578d7dc17d98de197e54c5a'] as $relative=>$sha)
    if(hash_file('sha256',$root.'/'.$relative)!==$sha) exit(78);
$boundary=json_decode((string)file_get_contents(
    'http://127.0.0.1:'.$port.'/__poc_boundary'),true);
if(($boundary['external_stubs']??null)!==true
    || ($boundary['redis_isolated']??null)!==true
    || ($boundary['real_queue']??null)!==false) exit(78);
$dsn=$lane==='B'
    ? 'mysql:host='.$workerEnv['POC_HOST'].';port='.$workerEnv['POC_PORT']
        .';dbname='.$workerEnv['POC_SCHEMA'].';charset=utf8'
    : 'dm:host=127.0.0.1;port=5237;schema=ZHCT_APP';
$db=new PDO($dsn,$workerEnv['POC_USER'],$workerEnv['POC_PASSWORD'],
    [PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER]);
if($lane==='C') {
    if(strtoupper((string)$db->query('SELECT USER FROM DUAL')->fetchColumn())!=='ZHCT_APP'
        || strtoupper((string)$db->query("SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL")->fetchColumn())!=='ZHCT_APP') exit(78);
} else if ((string)$db->query('SELECT DATABASE()')->fetchColumn()
    !==$workerEnv['POC_SCHEMA']) exit(78);
$p=$lane==='B'?'ydy_':'YDY_';
$one=static function(string $sql,array $args)use($db):array{
    $s=$db->prepare($sql);$s->execute($args);$rows=$s->fetchAll(PDO::FETCH_ASSOC);
    if(count($rows)!==1)throw new RuntimeException('Own row not unique');return $rows[0];
};
$all=static function(string $sql,array $args)use($db):array{
    $s=$db->prepare($sql);$s->execute($args);return $s->fetchAll(PDO::FETCH_ASSOC);
};
$rowHash=static function(array $row):string{
    ksort($row);return hash('sha256',json_encode($row,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES));
};
$writeReceipt=static function(string $path,array $events):void{
    $body=json_encode(['schema'=>1,'events'=>$events],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
    $tmp=$path.'.tmp';
    if(!is_string($body)||file_put_contents($tmp,$body,LOCK_EX)!==strlen($body)
        || !chmod($tmp,0600)||!rename($tmp,$path))
        throw new RuntimeException('Receipt persistence failed');
};
$marker='CDXSYNC'.strtoupper(bin2hex(random_bytes(5)));
$deptId=random_int(910000000,999999999);
$receiptPath=$receiptDir.'/store-sync-consumer-'.$marker.'.json';
$rawPath=$receiptDir.'/store-sync-consumer-raw-'.$marker.'.jsonl';
$events=[];
$save=static function(string $phase,array $info) use (&$events,$receiptPath,$marker,$lane,$writeReceipt):void{
    $events[]=['phase'=>$phase,'at_epoch'=>time(),'lane'=>$lane,'marker'=>$marker]+$info;
    $writeReceipt($receiptPath,$events);
};
$status='incomplete';$failure=null;$stage='own_mapping';$failureContext=[];
try {
    $staffBefore=$one('SELECT * FROM '.$p.'staff WHERE ai_user_id=? AND is_show=1',[$actorId]);
    $userBefore=$one('SELECT * FROM '.$p.'user WHERE ai_user_id=? AND is_delete=0',[$actorId]);
    if((string)$userBefore['staff_uuid']!==(string)$staffBefore['uuid'])
        throw new RuntimeException('Own Store mapping mismatch');
    $stage='department_boundary';
    $fixedBefore=$one('SELECT * FROM '.$p.'department WHERE source=2 AND department_id=10000 AND is_show=1',[]);
    if($all('SELECT * FROM '.$p.'department WHERE source=2 AND department_id=?',[$deptId])!==[])
        throw new RuntimeException('Synthetic department collision');
    $stage='own_mobile';
    $mobile=(string)$staffBefore['mobile'];
    $failureContext=['staff_mobile_nonempty'=>$mobile!=='',
        'user_mobile_nonempty'=>(string)$userBefore['mobile']!=='',
        'mobile_equal'=>$mobile===(string)$userBefore['mobile']];
    if($mobile!==(string)$userBefore['mobile'])
        throw new RuntimeException('Own mobile mismatch');
    if($mobile==='') {
        for($i=0;$i<5;$i++) {
            $candidate='199'.str_pad((string)random_int(0,99999999),8,'0',STR_PAD_LEFT);
            if($all('SELECT ID FROM '.$p.'staff WHERE mobile=?',[$candidate])===[]
                && $all('SELECT ID FROM '.$p.'user WHERE mobile=? OR account=?',
                    [$candidate,$candidate])===[]) {
                $mobile=$candidate;break;
            }
        }
        if($mobile==='')throw new RuntimeException('Unique synthetic mobile unavailable');
    }
    $stage='before_receipt';
    $save('before_http',['own_ai_user_id'=>$actorId,
        'own_store_staff_id'=>(int)$staffBefore['id'],
        'own_store_user_id'=>(int)$userBefore['id'],
        'synthetic_department_id'=>$deptId,
        'own_staff_sha256'=>$rowHash($staffBefore),
        'own_user_sha256'=>$rowHash($userBefore),
        'input_mobile_sha256'=>hash('sha256',$mobile),
        'shared_department_10000_sha256'=>$rowHash($fixedBefore),
        'synthetic_department_rows_before'=>0,
        'external_stubs'=>true,'redis_isolated'=>true]);
    $check=json_decode((string)file_get_contents($receiptPath),true);
    if(($check['events'][0]['phase']??null)!=='before_http')
        throw new RuntimeException('Before receipt not durable');
    $stage='api_signing';
    require $root.'/env.php';
    define('APP_PATH',$root.'/application/');
    require $root.'/thinkphp/base.php';
    $config=require $root.'/application/config.php';
    $sk=(string)($config['api_sk']??'');
    if($sk==='')throw new RuntimeException('Store API signing unavailable');
    $params=['hs_user_id'=>$actorId,'user_name'=>$marker,
        'department_id'=>$deptId,'department_name'=>$marker,
        'department_parent_id'=>-100,'mobile'=>$mobile,'source'=>3,
        'gender'=>2,'birthday'=>'1992-02-29','height'=>'171.50',
        'weight'=>'61.25'];
    $sorted=$params;ksort($sorted);$signature='';
    foreach($sorted as $key=>$value)$signature.=$key.$value;
    $params['sign']=md5($signature.$sk);
    unset($signature,$sk);
    $context=stream_context_create(['http'=>['method'=>'POST','timeout'=>15,
        'ignore_errors'=>true,'header'=>'Content-Type: application/x-www-form-urlencoded',
        'content'=>http_build_query($params)]]);
    $stage='http_request';
    $start=microtime(true);
    $raw=@file_get_contents('http://127.0.0.1:'.$port.'/api/user/sync',false,$context);
    $elapsed=(int)round((microtime(true)-$start)*1000);
    $line=$http_response_header[0]??'';
    $http=preg_match('/HTTP\/\S+\s+(\d+)/',$line,$matches)?(int)$matches[1]:0;
    if($http===0) {
        $barrier=@file_get_contents('http://127.0.0.1:'.$port.'/__poc_boundary');
        $save('timeout_barrier',['http'=>0,'elapsed_ms'=>$elapsed,
            'barrier_completed'=>is_string($barrier)]);
        throw new RuntimeException('Incomplete Store HTTP');
    }
    $rawRecord=['method'=>'POST','path'=>'/api/user/sync','http'=>$http,
        'request_field_names'=>array_keys($params),'response_raw'=>$raw];
    $json=json_encode($rawRecord,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)."\n";
    if(file_put_contents($rawPath,$json,LOCK_EX)!==strlen($json)
        ||!chmod($rawPath,0600))throw new RuntimeException('Raw response persistence failed');
    $body=is_string($raw)?json_decode($raw,true):null;
    $stage='after_readback';
    $staffAfter=$one('SELECT * FROM '.$p.'staff WHERE id=? AND ai_user_id=?',
        [(int)$staffBefore['id'],$actorId]);
    $userAfter=$one('SELECT * FROM '.$p.'user WHERE id=? AND ai_user_id=?',
        [(int)$userBefore['id'],$actorId]);
    $fixedAfter=$one('SELECT * FROM '.$p.'department WHERE source=2 AND department_id=10000 AND is_show=1',[]);
    $newDepartment=$all('SELECT * FROM '.$p.'department WHERE source=2 AND department_id=?',[$deptId]);
    $pass=$http===200 && is_array($body) && (int)($body['code']??-1)===0
        && (int)($body['data']['user_id']??0)===(int)$userBefore['id']
        && count($newDepartment)===1
        && (string)$staffAfter['name']===$marker
        && (string)$userAfter['name']===$marker
        && hash_equals(hash('sha256',$mobile),hash('sha256',(string)$staffAfter['mobile']))
        && hash_equals(hash('sha256',$mobile),hash('sha256',(string)$userAfter['mobile']))
        && (float)$staffAfter['weight']===61.25
        && $rowHash($fixedBefore)===$rowHash($fixedAfter);
    $save('after_http',['own_ai_user_id'=>$actorId,'http'=>$http,
        'business_code'=>is_array($body)?($body['code']??null):null,
        'elapsed_ms'=>$elapsed,'response_field_types'=>is_array($body)?array_map('gettype',$body):null,
        'response_user_id_type'=>gettype($body['data']['user_id']??null),
        'own_staff_sha256'=>$rowHash($staffAfter),
        'own_user_sha256'=>$rowHash($userAfter),
        'synthetic_department_rows_after'=>count($newDepartment),
        'synthetic_department_sha256'=>count($newDepartment)===1?$rowHash($newDepartment[0]):null,
        'shared_department_10000_sha256'=>$rowHash($fixedAfter),
        'shared_department_10000_unchanged'=>$rowHash($fixedBefore)===$rowHash($fixedAfter),
        'own_staff_and_user_name_match_synthetic'=>$staffAfter['name']===$marker&&$userAfter['name']===$marker,
        'own_staff_weight_matches_synthetic'=>(float)$staffAfter['weight']===61.25,
        'own_staff_mobile_matches_input'=>hash_equals(hash('sha256',$mobile),
            hash('sha256',(string)$staffAfter['mobile'])),
        'own_user_mobile_matches_input'=>hash_equals(hash('sha256',$mobile),
            hash('sha256',(string)$userAfter['mobile'])),
        'raw_response_sha256'=>hash('sha256',(string)$raw),'pass'=>$pass]);
    $status=$pass?'store_sync_consumer_http_db_pass':'store_sync_consumer_mismatch';
}catch(Throwable $error){$failure=['class'=>get_class($error),'stage'=>$stage,
    'safe_context'=>$failureContext];}
echo json_encode(['status'=>$status,'lane'=>$lane,'own_ai_user_id'=>$actorId,
    'receipt_path'=>$receiptPath,'receipt_sha256'=>is_file($receiptPath)?hash_file('sha256',$receiptPath):null,
    'raw_path'=>is_file($rawPath)?$rawPath:null,
    'raw_sha256'=>is_file($rawPath)?hash_file('sha256',$rawPath):null,
    'failure'=>$failure],JSON_UNESCAPED_SLASHES),PHP_EOL;
exit($status==='store_sync_consumer_http_db_pass'?0:4);
