<?php
/**
 * AURA FARMING — aferição interna de maioridade sem serviço terceirizado.
 * Não afirma identidade civil: combina declaração, e-mail, risco, dispositivo e revisão humana.
 */

function afAgeAssuranceCodeHash(string $code): string
{
    return hash_hmac('sha256', trim($code), SECURITY_HASH_SALT);
}

function afAgeAssuranceStatus(PDO $pdo, int $userId): array
{
    $profile = afBuscarPerfilIdade($pdo, $userId);
    if (!$profile) return ['ready'=>false,'code'=>'AGE_REQUIRED','message'=>'Confirme sua data de nascimento.','flags'=>['missing_age']];

    $status=(string)$profile['status_idade'];
    $type=(string)$profile['tipo_conta'];
    if (in_array($status,['adult_verified','guardian_verified'],true)) {
        return ['ready'=>true,'code'=>'VERIFIED','message'=>'Maioridade confirmada pelo fluxo interno.','flags'=>[]];
    }
    if ($type==='minor' || (int)$profile['idade_declarada']<18) {
        return ['ready'=>false,'code'=>'MINOR_ACCOUNT','message'=>'Conta classificada como menor.','flags'=>['minor']];
    }

    $st=$pdo->prepare('SELECT id,email,email_verificado_em,auth_provider,status,seguranca_status,risco_conta,suspenso_ate,data_cadastro FROM af_usuarios WHERE id=? LIMIT 1');
    $st->execute([$userId]);$u=$st->fetch()?:[];
    $emailOk=!empty($u['email_verificado_em']) || (!empty($u['auth_provider']) && (string)$u['auth_provider']!=='local');
    $flags=[];
    if(!$emailOk)$flags[]='email_not_verified';
    if((int)($u['status']??0)!==1)$flags[]='inactive_account';
    if(in_array((string)($u['seguranca_status']??'normal'),['restrito','banido'],true))$flags[]='security_restricted';
    if((int)($u['risco_conta']??0)>=40)$flags[]='high_account_risk';
    if(!empty($u['suspenso_ate']) && strtotime((string)$u['suspenso_ate'])>time())$flags[]='suspended';

    try{
        $st=$pdo->prepare("SELECT COUNT(*) attempts,COUNT(DISTINCT data_nascimento) variants FROM af_age_verifications WHERE usuario_id=? AND criado_em>=DATE_SUB(NOW(),INTERVAL 30 DAY)");
        $st->execute([$userId]);$a=$st->fetch()?:[];
        if((int)($a['attempts']??0)>3)$flags[]='many_age_attempts';
        if((int)($a['variants']??0)>1)$flags[]='birth_date_changed';
    }catch(Throwable $e){}

    try{
        $st=$pdo->prepare("SELECT COUNT(DISTINCT dc2.usuario_id)
            FROM af_dispositivo_contas dc1
            JOIN af_dispositivo_contas dc2 ON dc2.fingerprint_hash=dc1.fingerprint_hash AND dc2.usuario_id<>dc1.usuario_id
            JOIN af_user_age_profiles ap ON ap.usuario_id=dc2.usuario_id AND ap.tipo_conta='minor'
            WHERE dc1.usuario_id=? AND dc1.ultima_vez_em>=DATE_SUB(NOW(),INTERVAL 90 DAY)");
        $st->execute([$userId]);
        if((int)$st->fetchColumn()>0)$flags[]='device_shared_with_minor';
    }catch(Throwable $e){}

    if($type==='guardian')$flags[]='guardian_manual_review_required';
    $ready=$type==='adult' && !$flags;
    return [
        'ready'=>$ready,
        'code'=>$ready?'ASSURANCE_READY':($emailOk?'MANUAL_REVIEW_REQUIRED':'EMAIL_CONFIRMATION_REQUIRED'),
        'message'=>$ready?'Maioridade confirmada pelo fluxo interno.':($emailOk?'Sua declaração precisa de revisão de segurança.':'Confirme seu e-mail para concluir a aferição interna.'),
        'flags'=>$flags,
        'email_ok'=>$emailOk,
        'status'=>$status,
        'type'=>$type,
    ];
}

function afAgeAssuranceSendEmailCode(PDO $pdo, int $userId): void
{
    if(function_exists('afRateLimitOrFail')){
        afRateLimitOrFail($pdo,'adult_age_email_user',(string)$userId,4,3600,3600);
        afRateLimitOrFail($pdo,'adult_age_email_ip',clientIp(),12,3600,3600);
    }
    $profile=afBuscarPerfilIdade($pdo,$userId);
    if(!$profile || (int)$profile['idade_declarada']<18 || !in_array((string)$profile['tipo_conta'],['adult','guardian'],true))throw new RuntimeException('Esta conta não está no fluxo de confirmação de maioridade.');
    $st=$pdo->prepare('SELECT nome,email FROM af_usuarios WHERE id=? AND status=1 LIMIT 1');$st->execute([$userId]);$u=$st->fetch();
    if(!$u || !filter_var($u['email'],FILTER_VALIDATE_EMAIL))throw new RuntimeException('O e-mail da conta é inválido.');
    $code=(string)random_int(100000,999999);
    $pdo->prepare("UPDATE af_age_assurance_codes SET status='superseded',updated_at=NOW() WHERE usuario_id=? AND status='pending'")->execute([$userId]);
    $pdo->prepare("INSERT INTO af_age_assurance_codes(usuario_id,code_hash,status,attempts,max_attempts,expires_at,request_ip,request_device_uuid,created_at,updated_at) VALUES (?,?,'pending',0,5,DATE_ADD(NOW(),INTERVAL 10 MINUTE),?,?,NOW(),NOW())")
        ->execute([$userId,afAgeAssuranceCodeHash($code),clientIp(),substr(deviceUuid(),0,64)]);
    $html='<p>Olá, '.esc((string)$u['nome']).'.</p><p>Seu código de confirmação de maioridade no Aura Farming é:</p><p style="font-size:28px;font-weight:800;letter-spacing:6px">'.esc($code).'</p><p>O código expira em 10 minutos. Não compartilhe.</p>';
    if(!enviarEmailSimples((string)$u['email'],'Código de confirmação — Aura Farming',$html))throw new RuntimeException('Não foi possível enviar o código pelo servidor de e-mail.');
    if(function_exists('afLogSeguranca'))afLogSeguranca($pdo,'adult_age_email_code_sent',5,['channel'=>'email'],$userId);
}

function afAgeAssuranceVerifyEmailCode(PDO $pdo, int $userId, string $code): array
{
    $code=preg_replace('/\D/','',$code);
    if(strlen($code)!==6)throw new RuntimeException('Informe o código de seis números.');
    $pdo->beginTransaction();
    try{
        $st=$pdo->prepare("SELECT * FROM af_age_assurance_codes WHERE usuario_id=? AND status='pending' ORDER BY id DESC LIMIT 1 FOR UPDATE");$st->execute([$userId]);$row=$st->fetch();
        if(!$row)throw new RuntimeException('Solicite um novo código.');
        if(strtotime((string)$row['expires_at'])<=time()){
            $pdo->prepare("UPDATE af_age_assurance_codes SET status='expired',updated_at=NOW() WHERE id=?")->execute([(int)$row['id']]);
            throw new RuntimeException('O código expirou. Solicite outro.');
        }
        if((int)$row['attempts']>=(int)$row['max_attempts'])throw new RuntimeException('Limite de tentativas atingido. Solicite outro código.');
        if(!hash_equals((string)$row['code_hash'],afAgeAssuranceCodeHash($code))){
            $pdo->prepare("UPDATE af_age_assurance_codes SET attempts=attempts+1,status=IF(attempts+1>=max_attempts,'blocked','pending'),updated_at=NOW() WHERE id=?")->execute([(int)$row['id']]);
            throw new RuntimeException('Código incorreto.');
        }
        $pdo->prepare("UPDATE af_age_assurance_codes SET status='verified',verified_at=NOW(),verified_ip=?,verified_device_uuid=?,updated_at=NOW() WHERE id=?")
            ->execute([clientIp(),substr(deviceUuid(),0,64),(int)$row['id']]);
        $pdo->prepare('UPDATE af_usuarios SET email_verificado_em=COALESCE(email_verificado_em,NOW()),atualizado_em=NOW() WHERE id=?')->execute([$userId]);
        $profile=afBuscarPerfilIdade($pdo,$userId);
        if(!$profile)throw new RuntimeException('Perfil etário não encontrado.');
        $assurance=afAgeAssuranceStatus($pdo,$userId);
        if((string)$profile['tipo_conta']==='adult' && empty($assurance['flags'])){
            $old=(string)$profile['status_idade'];
            $pdo->prepare("UPDATE af_user_age_profiles SET status_idade='adult_verified',verificado_em=NOW(),atualizado_em=NOW() WHERE usuario_id=? AND tipo_conta='adult'")->execute([$userId]);
            $pdo->prepare("INSERT INTO af_age_verifications(usuario_id,metodo,resultado,data_nascimento,pais_residencia,idade_calculada,ip_address,user_agent,device_uuid,dados,criado_em) VALUES (?,'email_risk_assurance','adult',?,?,?,?,?,?,?,NOW())")
                ->execute([$userId,$profile['data_nascimento'],$profile['pais_residencia'],$profile['idade_declarada'],clientIp(),substr((string)($_SERVER['HTTP_USER_AGENT']??''),0,1000),substr(deviceUuid(),0,64),json_encode(['signals'=>'email+risk+device','civil_identity_verified'=>false],JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)]);
            $pdo->prepare("INSERT INTO af_age_status_history(usuario_id,status_anterior,status_novo,motivo,actor_usuario_id,dados,criado_em) VALUES (?,?,'adult_verified','confirmação interna por e-mail e sinais de risco',?, ?,NOW())")
                ->execute([$userId,$old,$userId,json_encode(['method'=>'email_risk_assurance'],JSON_UNESCAPED_UNICODE)]);
        }
        $pdo->commit();
    }catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    recarregarSessaoUsuario($pdo,$userId);
    return afAgeAssuranceStatus($pdo,$userId);
}
