<?php
declare(strict_types=1);
// Pure projection boundary only: real service methods + real connector class affinity,
// fixture query results, no PDO/SQL/HTTP/Auth/constructor execution.
$main='/workspace/zhct/zhctproject/ai_api';$mode=$argv[1]??'original';if(!in_array($mode,['original','candidate'],true))exit(78);require $main.'/vendor/autoload.php';
$candidate='/tmp/cdx-ai-scale-datetime-candidate-20261011/candidate';if($mode==='candidate')require $candidate.'/app/api/service/ScaleDateTimeResponse.php';
$serviceRoot=$mode==='candidate'?$candidate:$main;require $serviceRoot.'/app/api/service/WellandScale.php';require $serviceRoot.'/app/api/service/YunkangbaoScale.php';
final class FixtureResult{private $rows;public function __construct($rows){$this->rows=$rows;}public function toArray(){return $this->rows;}}
final class FixtureQuery{private $db;private $table;public function __construct($db,$table){$this->db=$db;$this->table=$table;$db->trace[]=['table',$table];}public function __call($m,$args){$this->db->trace[]=[$m,$args];return $this;}public function find(){if($this->table==='ydy_measurement_session_raw')return ['id'=>1,'data'=>'{"weight":72.75,"height":181.25,"bmi":22.14}'];return ['session_id'=>101,'start_time'=>$this->db->value,'vendor'=>$this->db->vendor,'device_type'=>'body_scale'];}public function select(){return new FixtureResult([['metric_code'=>'weight','value'=>'72.75','unit'=>'kg','segment'=>null,'algorithm_vendor'=>$this->db->vendor,'algorithm_version'=>'test1'],['metric_code'=>'height','value'=>'181.25','unit'=>'cm','segment'=>null,'algorithm_vendor'=>$this->db->vendor,'algorithm_version'=>'test1'],['metric_code'=>'bmi','value'=>'22.14','unit'=>null,'segment'=>null,'algorithm_vendor'=>$this->db->vendor,'algorithm_version'=>'test1'],['metric_code'=>'bfp','value'=>'18.5','unit'=>'%','segment'=>'left_arm','algorithm_vendor'=>$this->db->vendor,'algorithm_version'=>'test1']]);}}
trait FixtureConnection{public $value;public $vendor;public $trace=[];public function __construct($value,$vendor){$this->value=$value;$this->vendor=$vendor;}public function table($table){return new FixtureQuery($this,$table);}public function connect(array $config=[],$linkNum=0,$autoConnection=false):PDO{throw new RuntimeException('Pure test must never connect PDO');}public function getPdo(){throw new RuntimeException('Pure test must never acquire PDO');}}
final class FixtureDm extends \app\common\database\Dm{use FixtureConnection;}
final class FixtureMysql extends \think\db\connector\Mysql{use FixtureConnection;}
final class FixtureManager{public $primary;public $secondary;public $aliases=[];public function connect($alias){$this->aliases[]=$alias;if($alias!=='mysql_zhct')throw new RuntimeException('Service must use actual secondary alias');return $this->secondary;}}
function wantedDTO($time,$vendor){return ['session_id'=>101,'measured_at'=>$time,'vendor'=>$vendor,'device_type'=>'body_scale','algorithm_vendor'=>$vendor,'algorithm_version'=>'test1','summary'=>['weight'=>['value'=>72.75,'unit'=>'kg'],'height'=>['value'=>181.25,'unit'=>'cm'],'bmi'=>['value'=>22.14,'unit'=>null]],'segments'=>['left_arm'=>['bfp'=>['value'=>18.5,'unit'=>'%']]],'raw'=>['weight'=>72.75,'height'=>181.25,'bmi'=>22.14]];}
$vectors=[['dm.zero6','dm','2026-10-11 08:30:00.000000','2026-10-11 08:30:00'],['dm.leap','dm','2000-02-29 23:59:59.000000','2000-02-29 23:59:59'],['dm.nonzero','dm','2026-10-11 08:30:00.000001','2026-10-11 08:30:00.000001'],['dm.invalid','dm','2026-02-30 08:30:00.000000','2026-02-30 08:30:00.000000'],['dm.null','dm',null,null],['dm.integer','dm',1791669000,1791669000],['mysql.zero6','mysql','2026-10-11 08:30:00.000000','2026-10-11 08:30:00.000000'],['mysql.seconds','mysql','2026-10-11 08:30:00','2026-10-11 08:30:00']];
$results=[];$checks=0;foreach($vectors as [$name,$dialect,$input,$expected])foreach([['WellandScale','latest','welland'],['WellandScale','byDate','welland'],['YunkangbaoScale','latest','yunkangbao'],['YunkangbaoScale','byDate','yunkangbao']] as [$class,$method,$vendor]){$manager=new FixtureManager;$manager->secondary=$dialect==='dm'?new FixtureDm($input,$vendor):new FixtureMysql($input,$vendor);$manager->primary=$dialect==='dm'?new FixtureMysql($input,$vendor):new FixtureDm($input,$vendor);$container=new \think\Container;$container->instance('think\DbManager',$manager);\think\Container::setInstance($container);$service=(new ReflectionClass('app\\api\\service\\'.$class))->newInstanceWithoutConstructor();$out=$method==='latest'?$service->latest(46918):$service->byDate(46918,'2026-10-11');$ok=$out===wantedDTO($expected,$vendor)&&count($manager->aliases)>0&&count(array_unique($manager->aliases))===1&&$manager->aliases[0]==='mysql_zhct';$results[$name.'.'.$class.'.'.$method]=['passed'=>$ok,'actual_measured_at'=>$out['measured_at'],'expected_measured_at'=>$expected,'secondary_affinity'=>$dialect,'primary_affinity'=>$dialect==='dm'?'mysql':'dm','query_trace_sha256'=>hash('sha256',json_encode($manager->secondary->trace))];$checks++;}
if($mode==='candidate'){$dm=new FixtureDm(null,'welland');$mysql=new FixtureMysql(null,'welland');$edge=[['zero1','2026-10-11 08:30:00.0','2026-10-11 08:30:00'],['seconds','2026-10-11 08:30:00','2026-10-11 08:30:00'],['bad_hour','2026-10-11 24:00:00.000000','2026-10-11 24:00:00.000000'],['bad_second','2026-10-11 08:30:60.000000','2026-10-11 08:30:60.000000'],['bad_leap','1900-02-29 08:30:00.000000','1900-02-29 08:30:00.000000'],['zero_date','0000-00-00 00:00:00.000000','0000-00-00 00:00:00.000000'],['too_many_fraction','2026-10-11 08:30:00.0000000','2026-10-11 08:30:00.0000000'],['trailing_space','2026-10-11 08:30:00.000000 ','2026-10-11 08:30:00.000000 '],['bool',false,false],['array',['date'=>'2026-10-11'],['date'=>'2026-10-11']]];foreach($edge as [$name,$value,$expected]){$ok=\app\api\service\ScaleDateTimeResponse::measuredAt($value,$dm)===$expected&&\app\api\service\ScaleDateTimeResponse::measuredAt($value,$mysql)===$value;$results['helper.'.$name]=['passed'=>$ok];$checks++;}}
$failed=array_keys(array_filter($results,static function($r){return !$r['passed'];}));echo json_encode(['phase'=>$mode,'checks'=>$checks,'failures'=>$failed,'results'=>$results,'real_service_methods'=>true,'constructor_bypassed_for_pure_boundary'=>true,'fixture_queries_only'=>true,'PDO'=>0,'SQL'=>0,'HTTP'=>0,'Auth'=>0,'DMLDDL'=>0],JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),"\n";exit($failed?1:0);
