<?php
declare(strict_types=1);
require_once __DIR__.'/common.php';

pcApiMethod('POST');$payload=pcApiJson();pcApiRate($mysqli,'enrollment',12,300);$cfg=pcApiCfg($mysqli);
$code=strtoupper(pcApiText($payload['activation_code']??'',20));$fingerprint=strtolower(pcApiText($payload['fingerprint_hash']??'',64));$machineGuid=strtolower(pcApiText($payload['machine_guid_hash']??'',64));
$patrimony=pcApiText($payload['patrimonio']??'',50);$responsible=pcApiText($payload['responsavel_nome']??'',150);$department=pcApiText($payload['setor']??'',150);$hostname=pcApiText($payload['hostname']??'',100);$serial=pcApiText($payload['numero_serie']??'',120);
$type=strtoupper(pcApiText($payload['tipo']??'DESKTOP',30));if(!in_array($type,['DESKTOP','NOTEBOOK','ALL_IN_ONE','MINI_PC','WORKSTATION','THIN_CLIENT'],true))$type='DESKTOP';
$manufacturer=pcApiText($payload['fabricante']??'',120);$model=pcApiText($payload['modelo']??'',180);
if(!preg_match('/^[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$/',$code))pcApiOut(403,['ok'=>false,'message'=>'Codigo de ativacao invalido.']);
if(!preg_match('/^[a-f0-9]{64}$/',$fingerprint)||($machineGuid!==''&&!preg_match('/^[a-f0-9]{64}$/',$machineGuid)))pcApiOut(422,['ok'=>false,'message'=>'Identificacao segura da maquina invalida.']);
if($patrimony===''||$responsible===''||$department===''||$hostname==='')pcApiOut(422,['ok'=>false,'message'=>'Patrimonio, responsavel, setor e nome da maquina sao obrigatorios.']);

$token=bin2hex(random_bytes(32));$tokenHash=hash('sha256',$token);$ip=pcApiIp();$computerId=pcApiFindComputer($mysqli,$patrimony,$serial?:null,$hostname);
$mysqli->begin_transaction();
try{
    $row=$mysqli->query('SELECT enrollment_hash,enrollment_expires_at,enrollment_uses_remaining FROM ti_pc_config WHERE id=1 FOR UPDATE')->fetch_assoc();
    $valid=$row&&!empty($row['enrollment_hash'])&&hash_equals((string)$row['enrollment_hash'],hash('sha256',$code))&&(int)$row['enrollment_uses_remaining']>0&&!empty($row['enrollment_expires_at'])&&strtotime((string)$row['enrollment_expires_at'])>=time();
    if(!$valid){$mysqli->rollback();pcApiAudit($mysqli,'ATIVACAO_NEGADA',null,$hostname,'Codigo invalido, expirado ou esgotado.');pcApiOut(403,['ok'=>false,'message'=>'Codigo invalido, expirado ou sem ativacoes disponiveis.']);}

    if(!$computerId&&pcApiTable($mysqli,'ti_computadores')){
        $sectorId=null;if(pcApiTable($mysqli,'ti_setores')){$stmt=$mysqli->prepare('SELECT id FROM ti_setores WHERE nome=? LIMIT 1');$stmt->bind_param('s',$department);$stmt->execute();$sector=$stmt->get_result()->fetch_assoc();$stmt->close();if($sector)$sectorId=(int)$sector['id'];else{$actor='AGENTE_WINDOWS';$stmt=$mysqli->prepare('INSERT INTO ti_setores(nome,criado_por) VALUES(?,?)');$stmt->bind_param('ss',$department,$actor);$stmt->execute();$sectorId=(int)$stmt->insert_id;$stmt->close();}}
        $internal='EQP-AUTO-'.date('YmdHis').'-'.strtoupper(bin2hex(random_bytes(2)));$actor='AGENTE_WINDOWS';$mf=$manufacturer?:'Nao identificado';$mo=$model?:'Nao identificado';$serialValue=$serial?:null;
        $stmt=$mysqli->prepare("INSERT INTO ti_computadores(codigo_interno,tipo,patrimonio,numero_serie,nome_maquina,fabricante,modelo,responsavel_nome,setor_id,status,criado_por,atualizado_por) VALUES(?,?,?,?,?,?,?,?,NULLIF(?,0),'EM_USO',?,?)");
        $stmt->bind_param('ssssssssiss',$internal,$type,$patrimony,$serialValue,$hostname,$mf,$mo,$responsible,$sectorId,$actor,$actor);
        $stmt->execute();$computerId=(int)$stmt->insert_id;$stmt->close();
    }

    $stmt=$mysqli->prepare('SELECT * FROM ti_pc_agentes WHERE fingerprint_hash=? OR (computador_id IS NOT NULL AND computador_id=NULLIF(?,0)) ORDER BY computador_id IS NOT NULL DESC LIMIT 1 FOR UPDATE');$computerValue=$computerId??0;$stmt->bind_param('si',$fingerprint,$computerValue);$stmt->execute();$existing=$stmt->get_result()->fetch_assoc();$stmt->close();
    if($existing){$id=(int)$existing['id'];$agent=(string)$existing['agent_id'];$stmt=$mysqli->prepare("UPDATE ti_pc_agentes SET token_hash=?,token_issued_at=NOW(),fingerprint_hash=?,machine_guid_hash=NULLIF(?,''),computador_id=NULLIF(?,0),tipo=?,patrimonio=?,responsavel_nome=?,setor=?,hostname=?,numero_serie=NULLIF(?,''),fabricante=NULLIF(?,''),modelo=NULLIF(?,''),status='ATIVO',revogado_em=NULL,revogado_por=NULL,ultimo_ip_remoto=?,ultima_comunicacao=NOW() WHERE id=?");$stmt->bind_param('sssisssssssssi',$tokenHash,$fingerprint,$machineGuid,$computerValue,$type,$patrimony,$responsible,$department,$hostname,$serial,$manufacturer,$model,$ip,$id);$stmt->execute();$stmt->close();pcApiEvent($mysqli,$id,'REPROVISIONAMENTO','INFO','Agente Windows reprovisionado',null,null,'Novo token individual emitido.','ATIVACAO');}
    else{$stmt=$mysqli->prepare("INSERT INTO ti_pc_agentes(token_hash,fingerprint_hash,machine_guid_hash,computador_id,tipo,patrimonio,responsavel_nome,setor,hostname,numero_serie,fabricante,modelo,status,ultima_comunicacao,ultimo_ip_remoto) VALUES(?,?,NULLIF(?,''),NULLIF(?,0),?,?,?,?,?,NULLIF(?,''),NULLIF(?,''),NULLIF(?,''),'ATIVO',NOW(),?)");$stmt->bind_param('sssisssssssss',$tokenHash,$fingerprint,$machineGuid,$computerValue,$type,$patrimony,$responsible,$department,$hostname,$serial,$manufacturer,$model,$ip);$stmt->execute();$id=(int)$stmt->insert_id;$stmt->close();$agent='PC-'.date('Y').'-'.str_pad((string)$id,7,'0',STR_PAD_LEFT);$stmt=$mysqli->prepare('UPDATE ti_pc_agentes SET agent_id=? WHERE id=?');$stmt->bind_param('si',$agent,$id);$stmt->execute();$stmt->close();pcApiEvent($mysqli,$id,'REGISTRO','INFO','Novo computador registrado',null,$agent,'Agente Windows ativado.','ATIVACAO');}
    $mysqli->query('UPDATE ti_pc_config SET enrollment_uses_remaining=GREATEST(enrollment_uses_remaining-1,0) WHERE id=1');pcApiAudit($mysqli,$existing?'REPROVISIONAMENTO':'ATIVACAO',$id,$agent,'Token individual emitido; segredo omitido.');$mysqli->commit();
    pcApiOut(200,['ok'=>true,'agent_id'=>$agent,'token'=>$token,'computer_id'=>$computerId,'sync_interval_min'=>(int)($cfg['sync_interval_min']??30),'current_agent_version'=>(string)($cfg['current_agent_version']??'1.0.0'),'server_time'=>date(DATE_ATOM)]);
}catch(Throwable $error){$mysqli->rollback();pcApiOut(500,['ok'=>false,'message'=>'Nao foi possivel registrar o computador.']);}
