<?php
date_default_timezone_set('Asia/Shanghai');
$db=getenv('UPGRADE_TEST_DATABASE');if(!preg_match('/^upgrade_20261012_[0-9]+$/',$db))throw new RuntimeException('isolated database required');
$pdo=new PDO('mysql:host='.getenv('UPGRADE_TEST_HOST').';charset=utf8mb4','root',getenv('UPGRADE_TEST_PASSWORD'),[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);
$pdo->exec('CREATE DATABASE `'.$db.'` CHARACTER SET utf8mb4');$pdo->exec('USE `'.$db.'`');$pdo->exec("SET SESSION sql_mode=''");$pdo->exec("SET time_zone='+08:00'");
$f=json_decode(file_get_contents(__DIR__.'/sql-fixture.json'),true);$checks=0;
function check($ok,$name){global $checks;if(!$ok)throw new RuntimeException($name);$checks++;echo 'PASS '.$name.PHP_EOL;}
function seed($table,$override){global $pdo;$data=[];foreach($pdo->query('SHOW COLUMNS FROM `'.$table.'`')->fetchAll(PDO::FETCH_ASSOC) as $c){if($c['Extra']==='auto_increment'||$c['Default']!==null||$c['Null']==='YES')continue;$type=$c['Type'];$data[$c['Field']]=preg_match('/date|time/',$type)?'2000-01-01 00:00:00':(preg_match('/int|decimal|float|double/',$type)?0:'');}$data=array_merge($data,$override);$sql='INSERT INTO `'.$table.'` (`'.implode('`,`',array_keys($data)).'`) VALUES ('.implode(',',array_fill(0,count($data),'?')).')';$pdo->prepare($sql)->execute(array_values($data));return (int)$pdo->lastInsertId();}
function runSql($sql){global $pdo;foreach(explode(';',$sql) as $stmt){if(trim($stmt)!=='')$pdo->exec($stmt);}}
foreach($f['store'] as $schema)$pdo->exec($schema);
seed('ydy_meal_order',['id'=>1,'order_no'=>'UPGRADE-TEST','total_price'=>'12.50','pay_price'=>'12.50','pay_status'=>20,'pay_method'=>'balance']);
seed('ydy_restaurants',['id'=>1,'name'=>'TEST','morning_start'=>'00:00','morning_end'=>'10:00','noon_start'=>'10:01','noon_end'=>'16:00','night_start'=>'16:01','night_end'=>'19:30','night_snack_start'=>'19:31','night_snack_end'=>'23:59']);
$orderBefore=$pdo->query('SELECT * FROM ydy_meal_order WHERE id=1')->fetch(PDO::FETCH_ASSOC);$restaurantBefore=$pdo->query('SELECT * FROM ydy_restaurants WHERE id=1')->fetch(PDO::FETCH_ASSOC);
runSql($f['sql']['store1']);runSql($f['sql']['store2']);
$orderAfter=$pdo->query('SELECT * FROM ydy_meal_order WHERE id=1')->fetch(PDO::FETCH_ASSOC);$restaurantAfter=$pdo->query('SELECT * FROM ydy_restaurants WHERE id=1')->fetch(PDO::FETCH_ASSOC);
check(array_intersect_key($orderAfter,$orderBefore)===$orderBefore,'store migration preserves all existing order/payment values');
check($orderAfter['bank_user_name']==='','bank_user_name default is empty');
check(array_intersect_key($restaurantAfter,$restaurantBefore)===$restaurantBefore,'restaurant migration preserves screenshot meal times and other fields');
check((int)$restaurantAfter['night_snack_position']===1,'night_snack_position default is day end');
foreach(['store1','store2'] as $key){$duplicate=false;try{runSql($f['sql'][$key]);}catch(PDOException $e){$duplicate=(int)$e->errorInfo[1]===1060;}check($duplicate,$key.' must run once: rerun is duplicate-column error');}
foreach($f['ai_api'] as $schema)$pdo->exec($schema);
seed('yoshop_recharge_order',['order_id'=>101,'order_no'=>'RC-1','user_id'=>1,'store_id'=>1,'pay_time'=>strtotime('2026-10-01 12:00:00'),'create_time'=>strtotime('2026-10-01 11:00:00')]);
seed('yoshop_recharge_order',['order_id'=>102,'order_no'=>'RC-2','user_id'=>1,'store_id'=>1,'pay_time'=>0,'create_time'=>strtotime('2026-10-02 11:00:00')]);
foreach([
 ['consume','CO-1','',20,'2026-10-03 11:00:00'],['consume','CO-1','',20,'2026-10-03 12:00:00'],
 ['refund','CO-1','RF-1',20,'2026-10-04 12:00:00'],['consume','CO-FAILED','',30,'2026-10-05 12:00:00'],
] as $a)seed('yoshop_account_settlement',['settlement_no'=>'SET-'.uniqid(),'biz_type'=>$a[0],'biz_order_no'=>$a[1],'refund_no'=>$a[2],'status'=>$a[3],'create_time'=>$a[4],'user_id'=>1,'store_id'=>1,'amount'=>'5.00','gift_amount'=>'5.00']);
$cases=[
 [1,'recharge',101,'RC-1',1,1,'0000-00-00 00:00:00','2026-10-01 12:00:00'],
 [2,'recharge',102,'RC-2',1,1,'0000-00-00 00:00:00','2026-10-02 11:00:00'],
 [3,'consume',0,'CO-1',1,1,'0000-00-00 00:00:00','2026-10-03 12:00:00'],
 [4,'refund',0,'RF-1',1,1,'0000-00-00 00:00:00','2026-10-04 12:00:00'],
 [5,'recharge',101,'RC-1',1,1,'2026-10-06 08:00:00','2026-10-06 08:00:00'],
 [6,'recharge',101,'RC-1',2,1,'0000-00-00 00:00:00','0000-00-00 00:00:00'],
 [7,'recharge',101,'RC-1',1,2,'0000-00-00 00:00:00','0000-00-00 00:00:00'],
 [8,'consume',0,'NO-MATCH',1,1,'0000-00-00 00:00:00','0000-00-00 00:00:00'],
 [9,'consume',0,'CO-FAILED',1,1,'0000-00-00 00:00:00','0000-00-00 00:00:00'],
 [10,'recharge',999,'RC-1',1,1,'0000-00-00 00:00:00','0000-00-00 00:00:00'],
];
foreach($cases as $a)seed('yoshop_user_gift_log',['log_id'=>$a[0],'biz_type'=>$a[1],'biz_order_id'=>$a[2],'biz_order_no'=>$a[3],'store_id'=>$a[4],'user_id'=>$a[5],'create_time'=>$a[6],'update_time'=>'2026-10-07 00:00:00','money'=>'5.00','balance_before'=>'10.00','balance_after'=>'15.00','idempotency_key'=>'TEST-'.$a[0]]);
$before=$pdo->query('SELECT * FROM yoshop_user_gift_log ORDER BY log_id')->fetchAll(PDO::FETCH_ASSOC);
runSql($f['sql']['ai_api']);$after=$pdo->query('SELECT * FROM yoshop_user_gift_log ORDER BY log_id')->fetchAll(PDO::FETCH_ASSOC);
foreach($cases as $i=>$a){check($after[$i]['create_time']===$a[7],'gift history case '.$a[0].' timestamp match/isolation');$b=$before[$i];$c=$after[$i];unset($b['create_time'],$c['create_time']);check($b===$c,'gift history case '.$a[0].' preserves money/balances/update_time and all other fields');}
runSql($f['sql']['ai_api']);check($after===$pdo->query('SELECT * FROM yoshop_user_gift_log ORDER BY log_id')->fetchAll(PDO::FETCH_ASSOC),'gift history repair is idempotent');
echo 'PASS SQL upgrade '.$checks.' assertions; MySQL '.$pdo->query('SELECT VERSION()')->fetchColumn().'; isolated DB '.$db.' retained'.PHP_EOL;
