<?php
require __DIR__.'/common.php';
if(is_file(__DIR__.'/private/fixture-journal.json'))throw new RuntimeException('No fixture replay');
$journal=['lane'=>$lane,'approved_plan_sha256'=>'44a590f033b8017933aa590df7631da47707e97192bbc6ad338f2a6ca5392065','insert_sent'=>false,'committed'=>false];
require __DIR__.'/metadata.php';$catalogSame='FLcatalogSame';
if(hash_file('sha256',__DIR__.'/fixture-plan.json')!==$journal['approved_plan_sha256'])throw new RuntimeException('Plan drift');
$before=$source(true);$save('prewrite-source.json',$before);$expected=json_decode(file_get_contents(__DIR__.'/preflight-lease-'.$lane.'.json'),true)['datasets'];
foreach(['order','user','restaurant','operator']as $key){$current=$before[$key];$prior=$expected[$key];
    // Initial preflight JSON omitted PRESERVE_ZERO_FRACTION: only five declared zero DECIMAL
    // lease scalars lost float0/int0 information. Do not normalize HTTP/native batch records.
    if($lane==='C'&&in_array($key,['order','user'],true)){foreach($key==='order'?['refund_amount','cash_refund_amount','subsidy_refund_amount','gift_refund_amount']:['balance']as $field)if(($prior[0][$field]??null)===0&&($current[0][$field]??null)===0.0)$prior[0][$field]=0.0;}
    if($current!==$prior)throw new RuntimeException('Source lease drift '.$key);}
if($before['supplement']!==[]||$before['equipment']!==[])throw new RuntimeException('Marker or synthetic device collision');
if($q('SELECT id FROM ydy_meal_order_supplement WHERE meal_order_id=?',[$fixture['meal_order_id']])!==[])throw new RuntimeException('Existing supplement order reference');
$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',['ydy_meal_order_supplement']):$q('SELECT COLUMN_NAME,DATA_TYPE,DATA_LENGTH,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',['YDY_MEAL_ORDER_SUPPLEMENT']);
$old=json_decode(file_get_contents(__DIR__.'/preflight-'.$lane.'.json'),true)['schema']['store']['meal_order_supplement'];if(!($lane==='C'?$catalogSame($columns,$old):$columns===$old))throw new RuntimeException('Column drift');$save('fresh-columns.json',$columns);
if($lane==='B'){$triggers=$q('SELECT TRIGGER_NAME,ACTION_TIMING,EVENT_MANIPULATION,ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_SCHEMA=DATABASE() AND EVENT_OBJECT_TABLE=? ORDER BY TRIGGER_NAME',['ydy_meal_order_supplement']);$fks=$q("SELECT CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'",['ydy_meal_order_supplement']);if($columns[0]['extra']!=='auto_increment')throw new RuntimeException('No identity');}
else{$triggers=$q('SELECT * FROM USER_TRIGGERS WHERE TABLE_NAME=? ORDER BY TRIGGER_NAME',['YDY_MEAL_ORDER_SUPPLEMENT']);$fks=$q("SELECT CONSTRAINT_NAME FROM USER_CONSTRAINTS WHERE TABLE_NAME=? AND CONSTRAINT_TYPE='R'",['YDY_MEAL_ORDER_SUPPLEMENT']);if((int)$q("SELECT COUNT(*) AS n FROM USER_OBJECTS WHERE OBJECT_NAME='SP_TABLEDEF'")[0]['n']!==0)throw new RuntimeException('Shadow metadata routine');$s=$db->prepare('CALL SP_TABLEDEF(?, ?)');$s->bindValue(1,'ZHCT_APP',2);$s->bindValue(2,'YDY_MEAL_ORDER_SUPPLEMENT',2);$s->execute();$definition=$s->fetchColumn();$save('identity-definition.json',['queryString'=>$s->queryString,'binds'=>['ZHCT_APP','YDY_MEAL_ORDER_SUPPLEMENT'],'definition'=>$definition]);if(!preg_match('/"ID"\s+BIGINT\s+(?:AUTO_INCREMENT|IDENTITY\b)/i',$definition))throw new RuntimeException('No native identity');}
if($triggers!==[]||$fks!==[])throw new RuntimeException('Unexpected trigger/FK');
$indexBase=json_decode(file_get_contents(__DIR__.'/preflight-relations-'.$lane.'.json'),true)['schema'];
if($lane==='B'){$indexes=$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',['ydy_meal_order_supplement']);if($indexes!==$indexBase['supplement_indexes'])throw new RuntimeException('Index drift');}
else{$indexes=$q('SELECT INDEX_NAME,UNIQUENESS,INDEX_TYPE FROM USER_INDEXES WHERE TABLE_NAME=? ORDER BY INDEX_NAME',['YDY_MEAL_ORDER_SUPPLEMENT']);$indexCols=$q('SELECT INDEX_NAME,COLUMN_NAME,COLUMN_POSITION FROM USER_IND_COLUMNS WHERE TABLE_NAME=? ORDER BY INDEX_NAME,COLUMN_POSITION',['YDY_MEAL_ORDER_SUPPLEMENT']);if($indexes!==$indexBase['supplement_indexes']||!$catalogSame($indexCols,$indexBase['supplement_index_cols']))throw new RuntimeException('Index drift');}
$journal['sql']=$plan['sql'];$journal['values']=$fixture;$save('fixture-journal.json',$journal);
$db->beginTransaction();try{$s=$db->prepare($plan['sql']);foreach(array_values($fixture)as $i=>$v)$s->bindValue($i+1,$v,is_int($v)?1:($v===null?0:2));$journal['insert_sent']=true;$save('fixture-journal.json',$journal);$s->execute();$journal['rowCount']=$s->rowCount();$journal['errorInfo']=$s->errorInfo();$save('fixture-journal.json',$journal);if($s->rowCount()!==1)throw new RuntimeException('One INSERT only');$rows=$q('SELECT * FROM ydy_meal_order_supplement WHERE supplement_no=?',[$fixture['supplement_no']]);if(count($rows)!==1||(int)$rows[0]['id']<=0)throw new RuntimeException('Generated PK');$keys=array_keys($rows[0]);sort($keys);$expectedKeys=array_merge(['id'],array_keys($fixture));sort($expectedKeys);if($keys!==$expectedKeys)throw new RuntimeException('All physical columns');foreach($fixture as $k=>$v){$got=$rows[0][$k];$ok=is_int($v)?(is_numeric($got)&&(int)$got===$v):($v==='0.00'?is_numeric($got)&&(float)$got===0.0:$got===$v);if(in_array($k,['consume_time','create_time','update_time'],true))$ok=$got===$v||$got===$v.'.000000';if(!$ok)throw new RuntimeException('Original column '.$k);}$journal['original']=$rows[0];$db->commit();$journal['committed']=true;$save('fixture-journal.json',$journal);}catch(Throwable $e){if($db->inTransaction())$db->rollBack();$journal['error']=['class'=>get_class($e),'message'=>$e->getMessage()];$save('fixture-journal.json',$journal);throw $e;}
$after=$source(true);$save('batch-before.json',$after);$save('fixture-oracle.json',$GLOBALS['FL_ORACLE']);
echo json_encode(['lane'=>$lane,'insert'=>1,'rowCount'=>1,'id'=>$journal['original']['id'],'committed'=>true]),"\n";
