<?php
define('APP_PATH','/workspace/application/');require '/workspace/env.php';require '/workspace/thinkphp/base.php';require_once '/workspace/application/common.php';\think\Config::set(require APP_PATH.'database.php','database');\think\Config::set('meal_type',3);
\think\Db::execute('SET TRANSACTION READ ONLY');\think\Db::startTrans();
try {
 $p=\think\Config::get('database.prefix');$start='2026-09-12';$end='2026-10-12';$store=getStoreId();
 $events=\think\Db::query('SELECT DISTINCT r.menu_date,r.meal_times,r.dishes_uuid,d.id,d.name,d.cook_method,d.category_one,d.category_two,d.weight,d.protein,d.fat,d.dietary_fiber,d.purine FROM '.$p.'recipes r JOIN '.$p.'dishes d ON d.uuid=r.dishes_uuid WHERE r.restaurant_id=1 AND r.menu_date BETWEEN ? AND ? AND d.store_id=? AND d.is_del=1 AND d.status=1 AND d.is_delete=0 ORDER BY r.menu_date,r.meal_times,d.id',[$start,$end,$store]);
 $tags=\think\Db::query('SELECT dishes_id,nutrient,level FROM '.$p.'dishes_tag WHERE store_id=? AND is_delete=0 AND nutrient IN (?,?,?,?)',[$store,'protein','fat','dietary_fiber','purine']);
 $tagmap=[];foreach($tags as $t)$tagmap[$t['dishes_id']][$t['nutrient'].':'.$t['level']]=true;
 $dict=\think\Db::name('config_enum')->where('enum_type','4')->where('is_delete',0)->field('enum_key,enum_name,recommend,`order`')->select();
 $dict=is_array($dict)?$dict:$dict->toArray();usort($dict,function($a,$b){return (int)$a['order']<=>(int)$b['order'];});$cooks=array_column($dict,null,'enum_key');
 $food=\think\Db::query('SELECT r.dishes_uuid,SUM(CASE WHEN f.category IN (1,2) OR (f.category=12 AND f.category_two=57) THEN r.foods_ratio ELSE 0 END) staple,SUM(CASE WHEN f.category IN (6,7,8) THEN r.foods_ratio ELSE 0 END) vegetable,SUM(CASE WHEN f.category IN (3,4,5,10) THEN r.foods_ratio ELSE 0 END) meat,SUM(CASE WHEN f.category IN (9,11) OR (f.category=12 AND (f.category_two<>57 OR f.category_two IS NULL)) THEN r.foods_ratio ELSE 0 END) dairy FROM '.$p.'dish r JOIN '.$p.'foods_composition f ON f.id=r.foods_id AND f.store_id=r.store_id WHERE r.store_id=? AND r.is_delete=0 GROUP BY r.dishes_uuid',[$store]);$food=array_column($food,null,'dishes_uuid');
 $n=count($events);$counts=['protein'=>0,'fat'=>0,'dietary_fiber'=>0,'purine'=>0,'steam_boil_stew'=>0];$cookCounts=[];$recommended=0;$days=[];$tagMismatch=[];$missingFood=0;
 foreach($events as $e){
  $date=$e['menu_date'];if(!isset($days[$date]))$days[$date]=array_merge(['date'=>$date,'supply'=>0,'staple'=>0,'vegetable'=>0,'meat'=>0,'dairy'=>0],array_fill_keys(array_keys($counts),0));$days[$date]['supply']++;
  foreach(['protein:1','fat:3','dietary_fiber:1','purine:3'] as $tag){list($field)=explode(':',$tag);if(isset($tagmap[$e['id']][$tag])){$counts[$field]++;$days[$date][$field]++;}}
  $cook=$cooks[$e['cook_method']]??null;if(!$cook)throw new RuntimeException('Missing cooking dictionary');
  $name=$cook['enum_name'];if($name==='其他')$name=(int)$cook['recommend']===1?'推荐其他':'非推荐其他';$cookCounts[$name]=($cookCounts[$name]??0)+1;
  if((int)$cook['recommend']===1)$recommended++;
  if(in_array($name,['蒸','煮','炖'],true)){$counts['steam_boil_stew']++;$days[$date]['steam_boil_stew']++;}
  foreach(['staple','vegetable','meat','dairy'] as $group){$ratio=(float)($food[$e['dishes_uuid']][$group]??0);if($group==='dairy'?$ratio>0:$ratio>=50)$days[$date][$group]++;}
  $liquid=(int)$e['category_one']===17||(int)$e['category_two']===13;
  foreach(['protein'=>[1,$liquid?12:24],'fat'=>[3,$liquid?1.5:3],'dietary_fiber'=>[1,$liquid?3:6],'purine'=>[3,75]] as $field=>$rule){$v=$e['weight']>0?round($e[$field]*100/$e['weight'],2):0;$expected=$field==='fat'?$v<=$rule[1]:($field==='purine'?$v<$rule[1]:$v>=$rule[1]);$stored=isset($tagmap[$e['id']][$field.':'.$rule[0]]);if($expected!==$stored)$tagMismatch[$e['dishes_uuid'].':'.$field]=['dish'=>$e['name'],'field'=>$field,'per100'=>$v,'expected'=>$expected,'stored'=>$stored];}
 }
 $metrics=[];foreach($counts as $field=>$count)$metrics[$field]=['count'=>$count,'ratio'=>round($count*100/$n,2)];
 $actual=(new \app\p\logic\MenuNutrition)->analyze(1,$start,$end,null,false);
 $checks=['supply_count'=>$actual['supply_count']===$n,'trends'=>false,'cooking_count'=>$actual['cooking']['recommended_count']===$recommended,'cooking_ratio'=>$actual['cooking']['ratio']===round($recommended*100/$n,2)];
 $trendDiff=[];$expectedDays=array_values($days);
 foreach($expectedDays as $i=>$day)foreach($day as $field=>$value){if(!isset($actual['trends'][$i])||!array_key_exists($field,$actual['trends'][$i])||$actual['trends'][$i][$field]!==$value)$trendDiff[]=['date'=>$day['date'],'field'=>$field,'expected'=>$value,'actual'=>$actual['trends'][$i][$field]??null];}
 $checks['trends']=!$trendDiff&&count($actual['trends'])===count($expectedDays);
 foreach(['protein','fat','dietary_fiber','purine'] as $field)$checks[$field]=$actual['labels'][$field]['count']===$counts[$field]&&$actual['labels'][$field]['ratio']===round($counts[$field]*100/$n,2);
 foreach($actual['cooking']['list'] as $row)$checks['cook_'.$row['name']]=isset($cookCounts[$row['name']])&&$cookCounts[$row['name']]===$row['count']&&round($row['count']*100/$n,2)===$row['ratio'];
 $first=reset($days);$last=end($days);
 $screenshot=['supply_count'=>293,'protein'=>0,'fat'=>169,'dietary_fiber'=>10,'purine'=>273,'steam_boil_stew'=>116,'effective_days'=>23,'first_staple'=>3,'last_staple'=>11,'delta_staple'=>8];
 $oracle=array_merge(['supply_count'=>$n],$counts,['effective_days'=>count($days),'first_staple'=>$first['staple'],'last_staple'=>$last['staple'],'delta_staple'=>$last['staple']-$first['staple']]);$screenChecks=[];foreach($screenshot as $k=>$v)$screenChecks[$k]=$oracle[$k]===$v;
 echo json_encode(['filter'=>['restaurant_id'=>1,'start'=>$start,'end'=>$end],'independent'=>$oracle,'metrics'=>$metrics,'cooking'=>array_map(function($name,$count)use($n){return ['name'=>$name,'count'=>$count,'ratio'=>round($count*100/$n,2)];},array_keys($cookCounts),array_values($cookCounts)),'recommended'=>['count'=>$recommended,'ratio'=>round($recommended*100/$n,2)],'days'=>array_values($days),'screenshot_checks'=>$screenChecks,'response_checks'=>$checks,'trend_differences'=>$trendDiff,'nutrition_tag_mismatch_count'=>count($tagMismatch),'nutrition_tag_mismatches'=>array_values($tagMismatch)],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE).PHP_EOL;
 if(in_array(false,$screenChecks,true)||in_array(false,$checks,true)||$tagMismatch)throw new RuntimeException('Screenshot reconciliation failed');
}finally{\think\Db::rollback();}
