<?php
$dir=__DIR__.'/source/application/common/service/schoolNutrition/';
foreach (['NutritionMetricCatalog','NutritionReferenceCatalog','WeeklyNutritionEvaluator','RecommendationService','NutritionCandidateRanker'] as $c) require $dir.$c.'.php';
use app\common\service\schoolNutrition\NutritionMetricCatalog;
use app\common\service\schoolNutrition\NutritionReferenceCatalog;
use app\common\service\schoolNutrition\RecommendationService;
$r=new ReflectionClass(RecommendationService::class);
$s=$r->newInstanceWithoutConstructor();
$m=$r->getMethod('nutritionTargetEvaluation');
$m->setAccessible(true);
$context=['plan'=>['target_group_snapshot_payload'=>json_encode(['age_band'=>'6_8','nutrition_reference'=>(new NutritionReferenceCatalog)->referenceSnapshot('6_8')])]];
$metrics=array_fill_keys(NutritionMetricCatalog::codes(),'1');
$metrics=array_merge($metrics,['energy'=>'650','protein'=>'16','fat'=>'20','carbohydrate'=>'90']);
$candidates=[1=>[['id'=>1,'ranking_metrics'=>$metrics]]];
$lunch=['meal_date'=>'2026-09-28','meal_type'=>2,'dishes'=>[['dish_id'=>1]]];
$night=['meal_date'=>'2026-09-28','meal_type'=>4,'dishes'=>[['dish_id'=>1]]];
foreach (['lunch_only'=>[$lunch],'lunch_and_night'=>[$lunch,$night]] as $label=>$meals) {
 $result=$m->invoke($s,$context,$meals,$candidates);
 echo json_encode(['case'=>$label,'status'=>$result['status'],'energy'=>$result['evaluation']['metrics'][0]],JSON_UNESCAPED_UNICODE)."\n";
}
$candidates[1][0]['ranking_metrics']['fat']='0';
$result=$m->invoke($s,$context,[$lunch],$candidates);
echo json_encode(['case'=>'valid_zero_fat','fat'=>array_values(array_filter($result['evaluation']['metrics'],fn($r)=>$r['code']==='fat'))],JSON_UNESCAPED_UNICODE)."\n";

$ranker=new app\common\service\schoolNutrition\NutritionCandidateRanker;
$rules=[['metric'=>'protein','mode'=>'density','direction'=>'desc'],['metric'=>'iron','mode'=>'density','direction'=>'desc']];
$cs=[['id'=>1,'ranking_metrics'=>['energy'=>'100','protein'=>'10','iron'=>'20']],['id'=>2,'ranking_metrics'=>['energy'=>'100','protein'=>'20','iron'=>'10']],['id'=>3,'ranking_metrics'=>['energy'=>'100','protein'=>'30','iron'=>'30']]];
$out=$ranker->rank($cs,[],$rules);
echo json_encode(['case'=>'multi_metric_complete','actual'=>array_column($out['ordered'],'id'),'expected'=>[3,1,2],'evidence'=>$out['evidence']],JSON_UNESCAPED_UNICODE)."\n";
$cs[0]['ranking_metrics']['protein']=null;
$out=$ranker->rank($cs,[],[$rules[0]]);
echo json_encode(['case'=>'single_metric_one_missing','actual'=>array_column($out['ordered'],'id'),'expected'=>[1,2,3],'evidence'=>$out['evidence']],JSON_UNESCAPED_UNICODE)."\n";
$cs=[['id'=>1,'seasonal_ratio'=>'0'],['id'=>2,'seasonal_ratio'=>'70']];
$out=$ranker->rank($cs,[],[],[],true);
echo json_encode(['case'=>'season_display_only','actual'=>array_column($out['ordered'],'id'),'expected'=>[1,2]],JSON_UNESCAPED_UNICODE)."\n";
