<?php

declare(strict_types=1);

$mode=(string)($argv[1]??'');$journal=(string)($argv[2]??'');$self=(string)hash_file('sha256',__FILE__);
$recoveryApproved=$mode!=='--recover'||((string)getenv('CDX_GRW_RECOVER')==='ROOT_GIFT_RULE_RECOVER_B_V1'
    &&hash_equals($self,(string)getenv('CDX_GRW_RECOVER_SHA')));
if(count($argv)!==3||!in_array($mode,['--preflight','--recover'],true)
    ||!preg_match('~^/tmp/cdx-grw-b-[a-f0-9]{12}/recovery\.json$~D',$journal)
    ||!$recoveryApproved){
    echo json_encode(['status'=>'default_deny','connected'=>false,'dml'=>false]),PHP_EOL;exit(78);
}
if(!is_file($journal)||is_link($journal)||is_link(dirname($journal))
    ||(fileperms(dirname($journal))&0777)!==0700||(fileperms($journal)&0777)!==0600)
    throw new RuntimeException('Journal invalid');
$saved=json_decode((string)file_get_contents($journal),true);
if(!is_array($saved)||($saved['lane']??null)!=='B'||($saved['phase']??null)!=='deleted'
    ||($saved['recovery_blocker']??null)!=='unexpected_reference'
    ||!preg_match('/^CDXGRW[A-F0-9]{10}$/D',(string)($saved['marker']??''))
    ||(int)($saved['rule_id']??0)<=0)throw new RuntimeException('Journal ownership invalid');
$marker=(string)$saved['marker'];$id=(int)$saved['rule_id'];
$cfg=require'/Users/wiscourper/Documents/workspace/zhct/zhctproject/store/application/config/local/database.php';$ai=$cfg['ai_zhct'];
$connect=static function()use($cfg,$ai):PDO{return new PDO('mysql:host='.$ai['hostname'].';port='.($ai['hostport']??3306).';dbname='.$ai['database'].';charset='.($cfg['charset']??'utf8'),$ai['username'],$ai['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_CASE=>PDO::CASE_LOWER]);};
$db=$connect();$rule='yoshop_recharge_gift_rule';$log='yoshop_recharge_gift_rule_log';
$rows=static function(PDO$p,string$sql,array$args=[]):array{$s=$p->prepare($sql);$s->execute($args);$out=[];while(($r=$s->fetch(PDO::FETCH_ASSOC))!==false){$clean=[];foreach(array_change_key_case($r,CASE_LOWER)as$k=>$v)$clean[$k]=is_resource($v)?stream_get_contents($v):$v;ksort($clean);$out[]=$clean;}return$out;};
$count=static function(PDO$p,string$sql,array$args=[]):int{$s=$p->prepare($sql);$s->execute($args);return(int)$s->fetchColumn();};
$natural=static function(PDO$p)use($rows,$rule,$log):string{$rules=$rows($p,'SELECT * FROM '.$rule." WHERE STORE_ID=10001 AND RULE_NAME NOT LIKE 'CDXGRW%' ORDER BY RULE_ID");$logs=$rows($p,'SELECT * FROM '.$log." WHERE STORE_ID=10001 AND OPERATOR_NAME NOT LIKE 'CDXGRW%' ORDER BY LOG_ID");return hash('sha256',serialize([$rules,$logs]));};
$actions=array_column($rows($db,'SELECT ACTION FROM '.$log.' WHERE RULE_ID=? AND OPERATOR_NAME=? ORDER BY LOG_ID',[$id,$marker]),'action');
$owned=$count($db,'SELECT COUNT(*) FROM '.$rule.' WHERE RULE_ID=? AND RULE_NAME=? AND STORE_ID=10001 AND STATUS=2 AND IS_DELETE=1 AND UPDATE_BY=?',[$id,$marker.'UPDATED',$marker]);
$giftRefs=[];$s=$db->query("SELECT TABLE_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND COLUMN_NAME='gift_rule_id'");foreach($s->fetchAll(PDO::FETCH_ASSOC)as$r){$table=(string)$r['table_name'];if(!preg_match('/^yoshop_[a-z0-9_]+$/D',$table))throw new RuntimeException('Gift ref table invalid');$n=$count($db,'SELECT COUNT(*) FROM '.$table.' WHERE GIFT_RULE_ID=?',[$id]);if($n)$giftRefs[$table.'.gift_rule_id']=$n;}
$genericCollisions=[];$s=$db->query("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND COLUMN_NAME='rule_id' ORDER BY TABLE_NAME");foreach($s->fetchAll(PDO::FETCH_COLUMN)as$table){if(in_array($table,[$rule,$log],true))continue;$n=$count($db,'SELECT COUNT(*) FROM '.$table.' WHERE RULE_ID=?',[$id]);if($n)$genericCollisions[$table.'.rule_id']=$n;}
$comments=[];$s=$db->query("SELECT c.TABLE_NAME,c.COLUMN_COMMENT,t.TABLE_COMMENT FROM INFORMATION_SCHEMA.COLUMNS c JOIN INFORMATION_SCHEMA.TABLES t ON t.TABLE_SCHEMA=c.TABLE_SCHEMA AND t.TABLE_NAME=c.TABLE_NAME WHERE c.TABLE_SCHEMA=DATABASE() AND c.COLUMN_NAME='rule_id' AND c.TABLE_NAME NOT IN ('yoshop_recharge_gift_rule','yoshop_recharge_gift_rule_log') ORDER BY c.TABLE_NAME");foreach($s->fetchAll(PDO::FETCH_ASSOC)as$r)$comments[(string)$r['table_name']]=[(string)$r['column_comment'],(string)$r['table_comment']];
$giftSemantics=[];$s=$db->query("SELECT c.TABLE_NAME,c.COLUMN_COMMENT,t.TABLE_COMMENT FROM INFORMATION_SCHEMA.COLUMNS c JOIN INFORMATION_SCHEMA.TABLES t ON t.TABLE_SCHEMA=c.TABLE_SCHEMA AND t.TABLE_NAME=c.TABLE_NAME WHERE c.TABLE_SCHEMA=DATABASE() AND c.COLUMN_NAME='rule_id' AND c.TABLE_NAME IN ('yoshop_recharge_gift_rule','yoshop_recharge_gift_rule_log') ORDER BY c.TABLE_NAME");foreach($s->fetchAll(PDO::FETCH_ASSOC)as$r)$giftSemantics[(string)$r['table_name']]=[(string)$r['column_comment'],(string)$r['table_comment']];
$couponColumns=$count($db,"SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND TABLE_NAME='yoshop_coupon_issue_record' AND COLUMN_NAME IN ('coupon_id','coupon_name','issue_method')");
$couponRows=$rows($db,'SELECT * FROM yoshop_coupon_issue_record WHERE RULE_ID=? ORDER BY ID',[$id]);
$couponSha=hash('sha256',serialize($couponRows));
$markerRows=$count($db,'SELECT COUNT(*) FROM '.$rule." WHERE RULE_NAME LIKE 'CDXGRW%' OR CREATE_BY LIKE 'CDXGRW%' OR UPDATE_BY LIKE 'CDXGRW%'")+$count($db,'SELECT COUNT(*) FROM '.$log." WHERE OPERATOR_ID LIKE 'CDXGRW%' OR OPERATOR_NAME LIKE 'CDXGRW%'");
$ready=$owned===1&&$actions===['create','update','disable','delete']&&$giftRefs===[]&&$markerRows===5
    &&$genericCollisions===['yoshop_coupon_issue_record.rule_id'=>1]
    &&($comments['yoshop_coupon_issue_record']??null)===['规则ID','优惠券发放记录']
    &&($giftSemantics['yoshop_recharge_gift_rule']??null)===['赠送活动ID','充值赠送活动']
    &&($giftSemantics['yoshop_recharge_gift_rule_log']??null)===['赠送活动ID','充值赠送活动操作日志']
    &&$couponColumns===3&&count($couponRows)===1&&($saved['natural_sha']??null)===$natural($db);
if($mode==='--preflight'){echo json_encode(['status'=>$ready?'recover_ready':'recover_blocked','rule_owned'=>$owned,'actions'=>$actions,'gift_rule_refs'=>$giftRefs,'generic_rule_id_collisions'=>$genericCollisions,'generic_rule_id_semantics'=>$comments,'gift_rule_semantics'=>$giftSemantics,'coupon_semantic_columns'=>$couponColumns,'coupon_collision_rows'=>count($couponRows),'coupon_collision_sha'=>$couponSha,'marker_rows'=>$markerRows,'natural_unchanged'=>$saved['natural_sha']===$natural($db),'dml'=>false],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),PHP_EOL;exit($ready?0:3);}
if(!$ready)throw new RuntimeException('Recovery safety gate');
$db->beginTransaction();try{$s=$db->prepare('DELETE FROM '.$log.' WHERE RULE_ID=? AND OPERATOR_NAME=?');$s->execute([$id,$marker]);if($s->rowCount()!==4)throw new RuntimeException('Log cleanup mismatch');$s=$db->prepare('DELETE FROM '.$rule.' WHERE RULE_ID=? AND RULE_NAME=? AND STORE_ID=10001 AND STATUS=2 AND IS_DELETE=1 AND UPDATE_BY=?');$s->execute([$id,$marker.'UPDATED',$marker]);if($s->rowCount()!==1)throw new RuntimeException('Rule cleanup mismatch');$db->commit();}catch(Throwable$e){if($db->inTransaction())$db->rollBack();throw$e;}
$fresh=$connect();$couponAfter=$rows($fresh,'SELECT * FROM yoshop_coupon_issue_record WHERE RULE_ID=? ORDER BY ID',[$id]);$zero=$count($fresh,'SELECT COUNT(*) FROM '.$rule." WHERE RULE_NAME LIKE 'CDXGRW%' OR CREATE_BY LIKE 'CDXGRW%' OR UPDATE_BY LIKE 'CDXGRW%'")===0&&$count($fresh,'SELECT COUNT(*) FROM '.$log." WHERE OPERATOR_ID LIKE 'CDXGRW%' OR OPERATOR_NAME LIKE 'CDXGRW%'")===0&&$natural($fresh)===$saved['natural_sha']&&count($couponAfter)===1&&hash('sha256',serialize($couponAfter))===$couponSha;if(!$zero)throw new RuntimeException('Independent zero failed');unlink($journal);rmdir(dirname($journal));echo json_encode(['status'=>'recovered_independent_zero','marker_rows'=>0,'natural_unchanged'=>true,'coupon_collision_row_unchanged'=>true,'coupon_collision_sha'=>$couponSha,'private_journal_removed'=>true]),PHP_EOL;
