<?php
declare(strict_types=1);
require __DIR__.'/common.php';
$mode=$argv[1]??'';$db=smPdo();
$guard=static function(bool $ok,string $label):void {if(!$ok){throw new RuntimeException($label);}};
set_exception_handler(static function(Throwable $e) use($mode):void {
    smSave('root-column-error-'.$mode.'.json',['phase'=>$mode,'message'=>$e->getMessage()]);
    echo json_encode(['phase'=>$mode,'status'=>'failed','error_sha256'=>hash('sha256',$e->getMessage())]),PHP_EOL;exit(1);
});
$guard(getenv('SM7_LANE')==='C','Only approved DM target');
$plan=smLoad('schema-plan-private.json');
$originalNames=array_map(static function(array $c):string{return strtolower($c['column_name']);},$plan['all_columns']);
$guard($plan['table']==='ydy_restaurants'&&$plan['rows']===7&&count($originalNames)===35,'Frozen original target');
$guard(!in_array('night_snack_position',$originalNames,true),'Frozen column must be absent');
$guard($plan['original_rows_sha256']==='5d8323cfe6853d1caac5c9b0db53d6e4a341f266db4dcf365a8cabe2c53c8f93','Frozen old row pin');
$snapshot=static function() use($db,$originalNames):array {
    $meta=smRows($db,'SELECT COLUMN_NAME,DATA_TYPE,DATA_PRECISION,DATA_SCALE,NULLABLE,DATA_DEFAULT,DATA_LENGTH FROM USER_TAB_COLUMNS WHERE TABLE_NAME=? ORDER BY COLUMN_ID',['YDY_RESTAURANTS']);
    $constraints=smRows($db,'SELECT CONSTRAINT_NAME,CONSTRAINT_TYPE,SEARCH_CONDITION,STATUS,VALIDATED FROM USER_CONSTRAINTS WHERE TABLE_NAME=?',['YDY_RESTAURANTS']);
    $conscols=smRows($db,'SELECT CONSTRAINT_NAME,COLUMN_NAME,POSITION FROM USER_CONS_COLUMNS WHERE TABLE_NAME=?',['YDY_RESTAURANTS']);
    $indexes=smRows($db,'SELECT INDEX_NAME,UNIQUENESS FROM USER_INDEXES WHERE TABLE_NAME=?',['YDY_RESTAURANTS']);
    $indexcols=smRows($db,'SELECT INDEX_NAME,COLUMN_NAME,COLUMN_POSITION FROM USER_IND_COLUMNS WHERE TABLE_NAME=?',['YDY_RESTAURANTS']);
    $triggers=smRows($db,'SELECT TRIGGER_NAME,STATUS FROM USER_TRIGGERS WHERE TABLE_NAME=?',['YDY_RESTAURANTS']);
    $sql='SELECT '.implode(',',array_map(static function(string $s):string {return '"'.strtoupper($s).'"';},$originalNames)).' FROM "ZHCT_APP"."YDY_RESTAURANTS" ORDER BY "ID"';
    $hashes=[];foreach(smRows($db,$sql) as $r){ksort($r);$hashes[(string)$r['id']]=hash('sha256',json_encode($r,JSON_UNESCAPED_UNICODE|JSON_PRESERVE_ZERO_FRACTION|JSON_THROW_ON_ERROR));}
    return ['all_columns'=>$meta,'constraints'=>$constraints,'constraint_columns'=>$conscols,'indexes'=>$indexes,'index_columns'=>$indexcols,
        'triggers'=>$triggers,'original_row_sha256_by_pk'=>$hashes,'original_rows_sha256'=>hash('sha256',json_encode($hashes,JSON_THROW_ON_ERROR))];
};
$same=static function($a,$b):bool {return json_encode($a,JSON_PRESERVE_ZERO_FRACTION)===json_encode($b,JSON_PRESERVE_ZERO_FRACTION);};
$before=$snapshot();
$guard($same($before['original_row_sha256_by_pk'],$plan['original_row_sha256_by_pk']),'Original rows drift');
if($mode==='preflight'||$mode==='apply') {
    foreach(['all_columns','constraints','constraint_columns','indexes','index_columns','triggers'] as $key) {
        $guard($same($before[$key],$plan[$key]),'Frozen metadata drift:'.$key);
    }
    $guard((int)smRows($db,'SELECT COUNT(*) N FROM USER_CONSTRAINTS WHERE CONSTRAINT_NAME=?',['CDX_RSTR_NSNK_U'])[0]['n']===0,'Constraint name collision');
    if($mode==='preflight') {
        smSave('root-column-preflight.json',['passed'=>true,'old_snapshot'=>$before,'DDL'=>0]);
        echo '{"status":"preflight-pass","old_rows":7,"old_columns":35,"DDL":0}',PHP_EOL;exit;
    }
    $gate=smLoad('root-column-preflight.json');$guard($gate['passed']&&$same($gate['old_snapshot'],$before),'Fresh apply snapshot differs');
    $steps=[
        'ALTER TABLE "ZHCT_APP"."YDY_RESTAURANTS" ADD "NIGHT_SNACK_POSITION" SMALLINT DEFAULT 1 NOT NULL',
        'ALTER TABLE "ZHCT_APP"."YDY_RESTAURANTS" ADD CONSTRAINT "CDX_RSTR_NSNK_U" CHECK ("NIGHT_SNACK_POSITION" >= 0 AND "NIGHT_SNACK_POSITION" <= 255)',
        "COMMENT ON COLUMN \"ZHCT_APP\".\"YDY_RESTAURANTS\".\"NIGHT_SNACK_POSITION\" IS '夜宵时段位置：1当天末尾，2当天开头'",
    ];
    $journal=['phase'=>'apply','completed'=>[],'old_rows_sha256'=>$before['original_rows_sha256']];
    foreach($steps as $i=>$sql){$db->exec($sql);$journal['completed'][]=['step'=>$i+1,'sql_sha256'=>hash('sha256',$sql)];smSave('root-column-DDL-journal.json',$journal);}
}
$after=$snapshot();
$guard($same($after['original_row_sha256_by_pk'],$plan['original_row_sha256_by_pk']),'Old rows changed');
$guard(count($after['all_columns'])===36,'Expected exactly one new column');
$oldCols=[];$newCol=[];foreach($after['all_columns'] as $c){if(strtoupper($c['column_name'])==='NIGHT_SNACK_POSITION'){$newCol=$c;}else{$oldCols[]=$c;}}
$guard($same($oldCols,$plan['all_columns']),'Original column contracts changed');
$guard(strtoupper($newCol['data_type'])==='SMALLINT'&&$newCol['nullable']==='N'&&trim((string)$newCol['data_default'])==='1','New type/default/nullable');
$oldCons=[];$newCons=[];foreach($after['constraints'] as $c){if($c['constraint_name']==='CDX_RSTR_NSNK_U'){$newCons[]=$c;}else{$oldCons[]=$c;}}
$guard($same($oldCons,$plan['constraints'])&&count($newCons)===1,'Unexpected constraints changed');
$check=$newCons[0];$guard($check['constraint_type']==='C'&&$check['status']==='ENABLED'&&$check['validated']==='VALIDATED','New check disabled or unvalidated');
$guard(strpos($check['search_condition'],'255')!==false&&strpos($check['search_condition'],'0')!==false,'Unsigned domain constraint');
foreach(['indexes','index_columns','triggers'] as $key){$guard($same($after[$key],$plan[$key]),'Original indexes/triggers changed');}
$values=smRows($db,'SELECT NIGHT_SNACK_POSITION,COUNT(*) N FROM "ZHCT_APP"."YDY_RESTAURANTS" GROUP BY NIGHT_SNACK_POSITION');
$guard(count($values)===1&&(int)$values[0]['night_snack_position']===1&&(int)$values[0]['n']===7,'Existing rows default mismatch');
$comment=smRows($db,'SELECT COMMENTS FROM USER_COL_COMMENTS WHERE TABLE_NAME=? AND COLUMN_NAME=?',['YDY_RESTAURANTS','NIGHT_SNACK_POSITION']);
$guard(count($comment)===1&&$comment[0]['comments']==='夜宵时段位置：1当天末尾，2当天开头','Column comment mismatch');
smSave('root-column-final.json',['passed'=>true,'phase'=>$mode,'old_35_column_rows_unchanged'=>true,'after'=>$after,
    'new_column_values'=>$values,'comment'=>$comment,'DDL_steps'=>3,'business_DML'=>0]);
echo '{"status":"verified","old_rows_unchanged":7,"columns":36,"all_existing_new_values":1,"DDL_steps":3,"business_DML":0}',PHP_EOL;
