<?php
declare(strict_types=1);date_default_timezone_set('Asia/Shanghai');require __DIR__.'/contract.php';$db=smPdo();$sha=catSha();catActor($db);$out=[];$errors=[];
$try=static function($key,callable $fn)use(&$out,&$errors):void{try{$out[$key]=$fn();}catch(Throwable $error){$out[$key]=null;$errors[$key]=['class'=>get_class($error),'message_sha256'=>hash('sha256',$error->getMessage())];smSave('candidate-error-'.$key.'-private.json',['message'=>$error->getMessage()]);}};
$try('search',static function()use($db){$rows=smRows($db,smTop('SELECT id,uuid,name FROM ydy_dishes WHERE is_del=1 AND status=1 ORDER BY id',5));foreach($rows as $r){if(strpbrk($r['name'],"'%_\\")!==false){continue;}$foods=smRows($db,smTop('SELECT id FROM ydy_foods_composition WHERE name LIKE ? OR sub_name LIKE ?',101),['%'.$r['name'].'%','%'.$r['name'].'%']);if(count($foods)>100){continue;}$dishUuids=[];if($foods){$ids=array_column($foods,'id');$components=smRows($db,smTop('SELECT dishes_uuid FROM ydy_dish WHERE composition_ratio>10 AND composition_id IN ('.implode(',',array_fill(0,count($ids),'?')).')',101),$ids);if(count($components)>100){continue;}$dishUuids=array_values(array_unique(array_column($components,'dishes_uuid')));}$sql='SELECT COUNT(*) n FROM ydy_dishes WHERE is_del=1 AND status=1 AND (name LIKE ?';$args=['%'.$r['name'].'%'];if($dishUuids){$sql.=' OR uuid IN ('.implode(',',array_fill(0,count($dishUuids),'?')).')';$args=array_merge($args,$dishUuids);}$count=catCount($db,$sql.')',$args);if($count>0&&$count<=100){return $r+['food_count'=>count($foods),'dish_match_count'=>$count];}}return null;});
$try('card',static function()use($db){$rows=smRows($db,smTop('SELECT c.id,c.card_id,c.staff_uuid,s.name FROM ydy_staff_card c JOIN ydy_staff s ON s.uuid=c.staff_uuid WHERE c.is_delete=0 AND c.is_cancel=0 AND s.is_show=1 ORDER BY c.id',5));foreach($rows as $r){if(strpbrk($r['card_id'],'%_')!==false){continue;}$n=catCount($db,'SELECT COUNT(*) n FROM ydy_staff s LEFT JOIN ydy_staff_card c ON c.staff_uuid=s.uuid AND c.is_delete=0 AND c.is_cancel=0 WHERE s.is_show=1 AND c.card_id LIKE ?',['%'.$r['card_id'].'%']);$departments=smRows($db,'SELECT d.name FROM ydy_staff_department sd JOIN ydy_department d ON d.uuid=sd.department_uuid WHERE sd.staff_uuid=? AND d.is_show=1',[$r['staff_uuid']]);if($n===1&&count($departments)<=1){return $r;}}return null;});
$try('log',static function()use($db){$rows=smRows($db,smTop("SELECT id,card_id,operate_date FROM ydy_staff_card_log WHERE is_delete=0 AND card_id IS NOT NULL AND card_id<>'' ORDER BY id DESC",5));foreach($rows as $r){if(strpbrk($r['card_id'],'%_')!==false){continue;}$date=substr((string)$r['operate_date'],0,10);if(!preg_match('/^\d{4}-\d{2}-\d{2}$/D',$date)){continue;}$n=catCount($db,'SELECT COUNT(*) n FROM ydy_staff_card_log WHERE is_delete=0 AND card_id LIKE ? AND operate_date>=? AND operate_date<=?',['%'.$r['card_id'].'%',$date,$date]);if($n>0&&$n<=100){return $r+['date'=>$date,'source_count'=>$n];}}return null;});
$try('dining',static function()use($db){$departments=catCount($db,'SELECT COUNT(*) n FROM ydy_department WHERE leaf_flag=1 AND status=1 AND is_show=1');if($departments>100){throw new RuntimeException('Returned department set over frozen 100 cap');}$id=getenv('SM7_LANE')==='B'?77:12;$today=date('Y-m-d');$menus=catCount($db,'SELECT COUNT(*) n FROM ydy_date_menu WHERE menu_date=? AND restaurant_id=? AND meal_type=3',[$today,$id]);if($menus>100){throw new RuntimeException('Consumed menu set over frozen 100 cap');}return ['restaurant_id'=>$id,'date'=>$today,'leaf_department_count'=>$departments,'menu_count'=>$menus];});
$out['restaurant']=null;$errors['restaurant']=['class'=>'PendingSchemaContract','reason'=>'restaurants.night_snack_position target missing; root-only alignment'];
smSave('candidates-private.json',['lane'=>getenv('SM7_LANE'),'source_sha256'=>$sha,'candidates'=>$out,'errors'=>$errors,'new_fixture_dml'=>0,'ddl'=>0]);$available=[];foreach($out as $k=>$v){$available[$k]=$v!==null;}echo json_encode(['lane'=>getenv('SM7_LANE'),'candidate_available'=>$available,'error_classes'=>array_map(static function($e){return $e['class'];},$errors),'new_fixture_dml'=>0,'ddl'=>0]),PHP_EOL;
