<?php
declare(strict_types=1);
namespace app\store\service\store {
    // DB/network-free test double for the existing cache-derived operator ID.
    class User {public static function getLoginUserId():?int{return 2147001021;}}
}
namespace app\store\model\nutrition {
    final class SourceContractRow implements \ArrayAccess,\JsonSerializable {
        private $data;public function __construct(array $data){$this->data=$data;}
        public function offsetExists($k):bool{return array_key_exists($k,$this->data);}
        public function offsetGet($k){return $this->data[$k];}
        public function offsetSet($k,$v):void{$this->data[$k]=$v;}
        public function offsetUnset($k):void{unset($this->data[$k]);}
        public function toArray():array{return $this->data;}
        public function jsonSerialize(){return $this->data;}
    }
    class NutritionTarget {
        public static $row;
        public static function infos(array $where,array $with=[]){return self::$row;}
    }
}
namespace app\terminal\model\meal {
    class MealRecommend {public static $row=null;public static function getOne(array $where){return self::$row;}}
}
namespace {
    $root=$argv[1]??'';if(!is_dir($root.'/vendor'))throw new \RuntimeException('Pass actual ai_api source root');
    require $root.'/vendor/autoload.php';
    spl_autoload_register(static function(string $class) use ($root):void {
        foreach (['app\\'=>'/app/','cores\\'=>'/cores/'] as $prefix=>$dir) {
            if (strpos($class,$prefix)===0) {
                $file=$root.$dir.str_replace('\\','/',substr($class,strlen($prefix))).'.php';
                if (is_file($file)) {require $file;return;}
            }
        }
    },true,true);
    if(!function_exists('app_name')){function app_name():string{return 'store';}}
    if(!function_exists('getStoreId')){function getStoreId():int{return 2147001021;}}
    $same=static function($a,$b,string $m):void{if($a!==$b)throw new \RuntimeException($m);};
    $mode=$argv[2]??'all';$n=0;
    if($mode==='plan'||$mode==='all'){
        $model=new \app\store\model\nutrition\Nutrition;
        $input=['name'=>'CDXNT10_UNIT','use_number'=>'01','unit_id'=>1];
        $row=$model->createData($input,'CDXNT10_UNIT',801,'2030-04-02');
        $same($row['is_delete']??null,0,'New original-PC plan must explicitly persist active0 for DM NOT NULL without a default');$n++;
        $same($row['name'],$input['name'],'Plan name mutated');$same($row['use_number'],'01','Plan numeric text mutated');$n+=2;
        $same($row['user_id'],2147001021,'Creator operator semantics changed');$same($row['staff_id'],801,'Staff changed');$same($row['set_date'],'2030-04-02','Date changed');$n+=3;
        foreach([0,1,null] as $explicit){$payload=$input+['is_delete'=>$explicit];$original=$payload;$row=$model->createData($payload,'CDXNT10_UNIT',801,'2030-04-02');$same($row['is_delete'],$explicit,'Explicit existing is_delete input changed');$same($payload,$original,'Caller input mutated');$n+=2;}
    }
    if($mode==='target'||$mode==='all'){
        $service=(new \ReflectionClass(\app\store\service\nutrition\NutritionTarget::class))->newInstanceWithoutConstructor();
        $fields=['recommend_energy','morning_ratio','noon_ratio','night_ratio','carbohydrate_ratio','protein_ratio','fat_ratio'];
        foreach([['2345.67','25.50','44.50','30.00','52.50','22.50','25.00'],[2345.67,25.5,44.5,30,52.5,22.5,25]] as $values){
            $row=array_combine($fields,$values)+['id'=>7,'staff_id'=>801,'store_id'=>2147001021,'is_delete'=>0,'create_by'=>'CDXNT10_UNIT','set_date'=>'2030-04-02'];
            $obj=new \app\store\model\nutrition\SourceContractRow($row);\app\store\model\nutrition\NutritionTarget::$row=$obj;
            $out=$service->detail(801,'2030-04-02');$wire=json_decode((string)json_encode($out),true);$same($wire['recommend_energy'],'2345.67','Outer target energy must match original MySQL string');$n++;
            $want=array_combine($fields,['2345.67','25.50','44.50','30.00','52.50','22.50','25.00'])+['id'=>7,'staff_id'=>801,'store_id'=>2147001021,'is_delete'=>0,'create_by'=>'CDXNT10_UNIT','set_date'=>'2030-04-02'];
            $same($wire['nutrition_target'],$want,'Complete target serialization must preserve all non-whitelisted fields and fixed decimals');$n++;
            $same($obj->toArray(),$row,'Serializer mutated raw model/calculation inputs');$n++;
        }
        \app\store\model\nutrition\NutritionTarget::$row=null;\app\terminal\model\meal\MealRecommend::$row=null;
        $same($service->detail(801,'2030-04-02'),['recommend_energy'=>0,'nutrition_target'=>[]],'Empty original target fallback changed');$n++;
        foreach(['2345.67',2345.67] as $power){
            $raw=['recommend_power'=>$power];$obj=new \app\store\model\nutrition\SourceContractRow($raw);\app\terminal\model\meal\MealRecommend::$row=$obj;
            $same($service->detail(801,'2030-04-02'),['recommend_energy'=>'2345.67','nutrition_target'=>[]],'Existing recommended energy fallback must preserve MySQL fixed string');$n++;
            $same($obj->toArray(),$raw,'Fallback normalization mutated raw recommendation');$n++;
        }
        foreach([null,''] as $empty){
            $row=['recommend_energy'=>$empty,'id'=>7,'staff_id'=>801];\app\store\model\nutrition\NutritionTarget::$row=new \app\store\model\nutrition\SourceContractRow($row);
            $same(json_decode((string)json_encode($service->detail(801,'2030-04-02')),true),['recommend_energy'=>$empty,'nutrition_target'=>$row],'Nullable/empty/absent other target keys must not be invented');$n++;
        }
    }
    echo json_encode(['mode'=>$mode,'assertions'=>$n,'all_passed'=>true,'database_or_network_called'=>false]),"\n";
}
