<?php
declare(strict_types=1);

$root=dirname(__DIR__);$database='tmp_mobile_api_'.date('Ymd_His').'_'.bin2hex(random_bytes(3));$passwordFile=tempnam(sys_get_temp_dir(),'mobile-db-pass-');file_put_contents($passwordFile,'');
if(!preg_match('/^tmp_mobile_api_[0-9_]+_[a-f0-9]{6}$/',$database))throw new RuntimeException('Nome temporário inseguro.');
$db=new mysqli('127.0.0.1','root','');$db->set_charset('utf8mb4');$server=null;$pipes=[];
function sqlBatch(mysqli $db,string $sql):void{if(!$db->multi_query($sql))throw new RuntimeException($db->error);do{if($r=$db->store_result())$r->free();if(!$db->more_results())break;}while($db->next_result());if($db->errno)throw new RuntimeException($db->error);}
function requestJson(string $url,array $body,array $headers=[]):array{$headers=array_merge(['Content-Type: application/json','Accept: application/json'],$headers);$context=stream_context_create(['http'=>['method'=>'POST','header'=>implode("\r\n",$headers),'content'=>json_encode($body,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES),'ignore_errors'=>true,'timeout'=>10]]);$raw=file_get_contents($url,false,$context);$status=0;foreach($http_response_header??[] as $line)if(preg_match('/^HTTP\/\S+\s+(\d+)/',$line,$m)){$status=(int)$m[1];break;}return [$status,json_decode((string)$raw,true)?:[]];}
function authHeaders(string $agent,string $token,string $nonce):array{return ['Authorization: Bearer '.$token,'X-Agent-Token: '.$token,'X-Agent-Id: '.$agent,'X-Timestamp: '.time(),'X-Nonce: '.hash('sha256',$nonce)];}
function assertStatus(int $actual,int $expected,string $case):void{if($actual!==$expected)throw new RuntimeException("{$case}: HTTP {$actual}, esperado {$expected}");echo "OK {$case}: HTTP {$actual}\n";}
try{
 $db->query("CREATE DATABASE `{$database}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");$db->select_db($database);$sql=file_get_contents($root.'/SQL_INVENTARIO_MOBILE.sql');sqlBatch($db,(string)$sql);
 $db->query('CREATE TABLE telecom_smartphones(id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,patrimonio VARCHAR(60),numero_serie VARCHAR(120),imei1 VARCHAR(40),imei2 VARCHAR(40))');
 $db->query('CREATE TABLE ti_ativos(id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,codigo_ativo VARCHAR(32),patrimonio_normalizado VARCHAR(120),serie_normalizada VARCHAR(180),identificador_secundario VARCHAR(180))');
 $code='F52A-91BC-729D';$hash=hash('sha256',$code);$stmt=$db->prepare('UPDATE ti_mobile_config SET enrollment_hash=?,enrollment_expires_at=DATE_ADD(NOW(),INTERVAL 1 HOUR),enrollment_uses_remaining=2 WHERE id=1');$stmt->bind_param('s',$hash);$stmt->execute();$stmt->close();
 $env=array_merge(getenv(),['MANUTENCAO_DB_HOST'=>'127.0.0.1','MANUTENCAO_DB_USER'=>'root','MANUTENCAO_DB_PASS_FILE'=>$passwordFile,'MANUTENCAO_DB_NAME'=>$database]);$null='NUL';$log=$root.'/tests/api-server.log';file_put_contents($log,'');$server=proc_open([PHP_BINARY,'-S','127.0.0.1:8098','-t',$root],[0=>['file',$null,'r'],1=>['file',$log,'a'],2=>['file',$log,'a']],$pipes,$root,$env,['bypass_shell'=>true]);if(!is_resource($server))throw new RuntimeException('Servidor PHP de teste não iniciou.');
 $ready=false;for($i=0;$i<50;$i++){$socket=@fsockopen('127.0.0.1',8098,$eno,$estr,.2);if(is_resource($socket)){fclose($socket);$ready=true;break;}usleep(100000);}if(!$ready)throw new RuntimeException('Servidor PHP recusou conexão: '.(is_file($log)?file_get_contents($log):'sem log'));$base='http://127.0.0.1:8098/api/tablets/';
 $register=['activation_code'=>$code,'fingerprint_hash'=>hash('sha256','device-a'),'android_id_hash'=>hash('sha256','android-a'),'device_type'=>'TABLET','patrimonio'=>'065544','responsavel_nome'=>'Carlos Eduardo','setor'=>'EMETI Nildes','numero_serie_manual'=>'SERIE-1','imei_manual'=>'','observacoes'=>'Teste automatizado'];
 $invalid=$register;$invalid['activation_code']='0000-0000-0000';[$status]=requestJson($base.'registrar.php',$invalid);assertStatus($status,403,'código inválido');
 [$status,$first]=requestJson($base.'registrar.php',$register);assertStatus($status,200,'primeira ativação');$agent=(string)$first['agent_id'];$oldToken=(string)$first['token'];
 [$status,$second]=requestJson($base.'registrar.php',$register);assertStatus($status,200,'ativação duplicada controlada');if($second['agent_id']!==$agent||$second['token']===$oldToken)throw new RuntimeException('Reprovisionamento não preservou Agent ID ou não rotacionou token.');$token=(string)$second['token'];
 [$status]=requestJson($base.'registrar.php',$register);assertStatus($status,403,'código expirado por uso');
 $inventory=['device_type'=>'TABLET','manufacturer'=>'Samsung','brand'=>'Samsung','model'=>'Galaxy Tab A9+','device_name'=>'gta9p','android_version'=>'14','sdk_int'=>34,'security_patch'=>'2024-01-01','build_id'=>'TEST','build_fingerprint'=>'test/fingerprint','architecture'=>'arm64-v8a','cpu_cores'=>8,'ram_total_mb'=>8192,'ram_available_mb'=>4096,'storage_total_mb'=>131072,'storage_free_mb'=>8000,'battery_percent'=>83,'battery_charging'=>false,'battery_temperature'=>31.5,'battery_status'=>'DESCARREGANDO','battery_source'=>'BATERIA','network_type'=>'WI-FI','local_ip'=>'192.168.10.54','screen_resolution'=>'1920x1200','screen_density'=>'240 dpi','app_version'=>'1.0.0','app_version_code'=>1,'collected_at'=>date('Y-m-d H:i:s'),'apps'=>[['package'=>'com.android.chrome','label'=>'Google Chrome','installed'=>false,'version_name'=>'','version_code'=>0,'system_app'=>false]]];
 [$status]=requestJson($base.'sincronizar.php',$inventory,authHeaders($agent,str_repeat('0',64),'bad-token'));assertStatus($status,401,'token inválido');
 $headers=authHeaders($agent,$token,'sync-1');[$status]=requestJson($base.'sincronizar.php',$inventory,$headers);assertStatus($status,200,'sincronização completa');[$status]=requestJson($base.'sincronizar.php',$inventory,$headers);assertStatus($status,409,'nonce repetido');
 $inventory['android_version']='15';[$status]=requestJson($base.'sincronizar.php',$inventory,authHeaders($agent,$token,'sync-2'));assertStatus($status,200,'mudança de Android');
 $events=(int)$db->query("SELECT COUNT(*) c FROM ti_mobile_eventos WHERE tipo IN ('ARMAZENAMENTO_CRITICO','APP_OBRIGATORIO_AUSENTE','MUDANCA_ANDROID_VERSION')")->fetch_assoc()['c'];if($events<3)throw new RuntimeException('Alertas/mudanças automáticos não foram criados.');echo "OK alertas automáticos: {$events}\n";
 $stmt=$db->prepare("UPDATE ti_mobile_dispositivos SET status='REVOGADO' WHERE agent_id=?");$stmt->bind_param('s',$agent);$stmt->execute();$stmt->close();[$status]=requestJson($base.'heartbeat.php',[],authHeaders($agent,$token,'revoked'));assertStatus($status,403,'token revogado');
 $stmt=$db->prepare("UPDATE ti_mobile_dispositivos SET status='ATIVO',ultima_comunicacao=DATE_SUB(NOW(),INTERVAL 10 DAY) WHERE agent_id=?");$stmt->bind_param('s',$agent);$stmt->execute();$stmt->close();[$status]=requestJson($base.'heartbeat.php',[],authHeaders($agent,$token,'return-online'));assertStatus($status,200,'retorno após offline');
 $recent=(int)$db->query("SELECT ultima_comunicacao>=DATE_SUB(NOW(),INTERVAL 1 MINUTE) ok FROM ti_mobile_dispositivos WHERE agent_id='{$db->real_escape_string($agent)}'")->fetch_assoc()['ok'];if(!$recent)throw new RuntimeException('Heartbeat não atualizou a comunicação.');
 echo "API TEST OK\nAgent ID {$agent}; histórico, replay, revogação e retorno validados.\n";
}finally{
 if(is_resource($server)){proc_terminate($server);proc_close($server);} $db->select_db('mysql');if(str_starts_with($database,'tmp_mobile_api_'))$db->query("DROP DATABASE IF EXISTS `{$database}`");$db->close();if(is_string($passwordFile)&&str_starts_with(basename($passwordFile),'mobile-db-pass-'))@unlink($passwordFile);
}
?>
