<?php
/**
 * AURA FARMING — Etapa 16
 * Conta do responsável, convite e vínculo inicial com o menor.
 * O vínculo NÃO libera câmera, Farm, Battle, live ou compartilhamento.
 */

function afGuardianNormalizarParentesco(string $parentesco): string
{
    $parentesco = strtolower(trim(strip_tags($parentesco)));
    $permitidos = [
        'mae' => 'Mãe', 'mãe' => 'Mãe', 'pai' => 'Pai',
        'avo' => 'Avô/Avó', 'avô' => 'Avô/Avó', 'avó' => 'Avô/Avó',
        'tutor' => 'Tutor legal', 'tutora' => 'Tutor legal', 'responsavel' => 'Responsável legal',
        'responsável' => 'Responsável legal', 'outro' => 'Outro responsável',
    ];
    return $permitidos[$parentesco] ?? 'Responsável legal';
}

function afGuardianBuscarConta(PDO $pdo, int $usuarioId): ?array
{
    $st = $pdo->prepare('SELECT ga.*,u.nome,u.email,u.aura_id,a.tipo_conta,a.status_idade,a.idade_declarada
        FROM af_guardian_accounts ga
        JOIN af_usuarios u ON u.id=ga.usuario_id
        LEFT JOIN af_user_age_profiles a ON a.usuario_id=u.id
        WHERE ga.usuario_id=? LIMIT 1');
    $st->execute([$usuarioId]);
    return $st->fetch() ?: null;
}

function afGuardianUsuarioPodeSerResponsavel(PDO $pdo, int $usuarioId): bool
{
    $age = afResumoIdade($pdo,$usuarioId);
    return $age['completo'] && (int)($age['idade'] ?? 0) >= 18
        && in_array($age['status'],['adult_declared','adult_verified','guardian_declared','guardian_verified'],true);
}

function afGuardianGarantirConta(PDO $pdo, int $usuarioId, ?string $telefone=null, string $origem='web'): array
{
    if (!afGuardianUsuarioPodeSerResponsavel($pdo,$usuarioId)) {
        throw new RuntimeException('A conta do responsável precisa pertencer a uma pessoa maior de 18 anos com idade confirmada.');
    }
    $telefone = trim(strip_tags((string)$telefone));
    $telefone = $telefone !== '' ? substr($telefone,0,30) : null;
    $pdo->prepare('INSERT INTO af_guardian_accounts (usuario_id,telefone,status_verificacao,origem,criado_em,atualizado_em)
        VALUES (?,? ,\'pending\',?,NOW(),NOW())
        ON DUPLICATE KEY UPDATE telefone=COALESCE(VALUES(telefone),telefone),atualizado_em=NOW()')
        ->execute([$usuarioId,$telefone,$origem]);
    return afGuardianBuscarConta($pdo,$usuarioId) ?: [];
}

function afGuardianBuscarVinculoDoMenor(PDO $pdo, int $minorUsuarioId): ?array
{
    $st=$pdo->prepare("SELECT l.*,u.nome guardian_nome,u.email guardian_email,u.aura_id guardian_aura_id,
        ga.telefone guardian_telefone,ga.status_verificacao guardian_status
        FROM af_guardian_minor_links l
        JOIN af_usuarios u ON u.id=l.guardian_usuario_id
        LEFT JOIN af_guardian_accounts ga ON ga.usuario_id=l.guardian_usuario_id
        WHERE l.minor_usuario_id=? AND l.status IN ('pending_verification','verified_pending_consent','active')
        ORDER BY l.id DESC LIMIT 1");
    $st->execute([$minorUsuarioId]);
    $link=$st->fetch() ?: null;
    if($link && function_exists('afGuardianAdultVerified') && !afGuardianAdultVerified($pdo,(int)$link['guardian_usuario_id'])){
        $link['guardian_status']='pending';
    }
    if($link && function_exists('afGuardianFamilyLinkConfirmed') && !afGuardianFamilyLinkConfirmed($pdo,(int)$link['id'])){
        $link['family_confirmed_at']=null;
    }
    return $link;
}

function afGuardianBuscarConvitePendenteDoMenor(PDO $pdo, int $minorUsuarioId): ?array
{
    $pdo->prepare("UPDATE af_guardian_invitations SET status='expired',atualizado_em=NOW()
        WHERE minor_usuario_id=? AND status='pending' AND expira_em<=NOW()")
        ->execute([$minorUsuarioId]);
    $st=$pdo->prepare("SELECT * FROM af_guardian_invitations
        WHERE minor_usuario_id=? AND status='pending' AND expira_em>NOW()
        ORDER BY id DESC LIMIT 1");
    $st->execute([$minorUsuarioId]);
    return $st->fetch() ?: null;
}

function afGuardianResumoDoMenor(PDO $pdo, int $minorUsuarioId): array
{
    $link=afGuardianBuscarVinculoDoMenor($pdo,$minorUsuarioId);
    $invite=$link ? null : afGuardianBuscarConvitePendenteDoMenor($pdo,$minorUsuarioId);
    $consent=null;
    if ($link && function_exists('afConsentResumoDoVinculo')) {
        try { $consent=afConsentResumoDoVinculo($pdo,(int)$link['id']); } catch (Throwable $e) { $consent=null; }
    }
    $etapa='not_started';
    if ($link) {
        if (!empty($consent['active'])) $etapa='consent_recorded_safety_pending';
        elseif ((string)($link['guardian_status']??'')==='verified') $etapa='guardian_verified_pending_consent';
        else $etapa='verification_pending';
    } elseif ($invite) $etapa='invitation_pending';
    return [
        'vinculado'=>(bool)$link,
        'vinculo'=>$link,
        'convite_pendente'=>(bool)$invite,
        'convite'=>$invite,
        'consent'=>$consent,
        'etapa'=>$etapa,
        'recursos_liberados'=>false,
    ];
}

function afGuardianCriarConvite(PDO $pdo,int $minorUsuarioId,string $nome,string $email,string $telefone,string $parentesco): array
{
    $age=afResumoIdade($pdo,$minorUsuarioId);
    if(!$age['completo'] || $age['tipo_conta']!=='minor') {
        throw new RuntimeException('Somente uma conta classificada como menor pode solicitar um responsável.');
    }
    if(afGuardianBuscarVinculoDoMenor($pdo,$minorUsuarioId)) {
        throw new RuntimeException('Esta conta já possui um responsável vinculado.');
    }
    $nome=trim(strip_tags($nome));
    $email=strtolower(trim($email));
    $telefone=trim(strip_tags($telefone));
    if(mb_strlen($nome)<3 || mb_strlen($nome)>120) throw new InvalidArgumentException('Informe o nome completo do responsável.');
    if(!filter_var($email,FILTER_VALIDATE_EMAIL)) throw new InvalidArgumentException('Informe um e-mail válido do responsável.');
    if($telefone!=='' && (mb_strlen($telefone)<8 || mb_strlen($telefone)>30)) throw new InvalidArgumentException('Informe um telefone válido ou deixe o campo vazio.');
    $parentesco=afGuardianNormalizarParentesco($parentesco);
    afRateLimitOrFail($pdo,'guardian_invite_minor',(string)$minorUsuarioId,3,3600,3600);
    afRateLimitOrFail($pdo,'guardian_invite_ip',clientIp(),8,3600,3600);

    $raw=bin2hex(random_bytes(32));
    $hash=hash('sha256',$raw);
    $hours=48;
    try{
        $st=$pdo->prepare("SELECT valor FROM af_configuracoes WHERE chave='guardian_invitation_expiration_hours' LIMIT 1");
        $st->execute();$hours=max(1,min(168,(int)($st->fetchColumn()?:48)));
    }catch(Throwable $e){}

    $expiraEm=(new DateTimeImmutable('now',new DateTimeZone(APP_TIMEZONE)))->modify('+'.$hours.' hours')->format('Y-m-d H:i:s');
    $pdo->beginTransaction();
    try{
        $pdo->prepare("UPDATE af_guardian_invitations SET status='cancelled',cancelado_em=NOW(),atualizado_em=NOW()
            WHERE minor_usuario_id=? AND status='pending'")->execute([$minorUsuarioId]);
        $st=$pdo->prepare("INSERT INTO af_guardian_invitations
            (minor_usuario_id,guardian_nome,guardian_email,guardian_telefone,parentesco,token_hash,status,tentativas_envio,enviado_em,expira_em,ip_criacao,device_uuid,criado_em,atualizado_em)
            VALUES (?,?,?,?,?,?,'pending',1,NOW(),?,?,?,NOW(),NOW())");
        $st->execute([$minorUsuarioId,$nome,$email,$telefone?:null,$parentesco,$hash,$expiraEm,clientIp(),deviceUuid()]);
        $id=(int)$pdo->lastInsertId();
        $pdo->commit();
    }catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}

    $st=$pdo->prepare('SELECT nome,aura_id FROM af_usuarios WHERE id=?');$st->execute([$minorUsuarioId]);$minor=$st->fetch()?:[];
    $link=SITE_URL.'/pages/convite-responsavel.php?token='.rawurlencode($raw);
    $assunto='Convite para ser responsável no Aura Farming';
    $html='<div style="font-family:Arial,sans-serif;max-width:560px;margin:auto;background:#080b14;color:#fff;padding:28px;border-radius:18px">'
        .'<h2 style="color:#36d8ff">AURA FARMING</h2><p>Olá, '.esc($nome).'.</p><p><b>'.esc((string)($minor['nome']??'Um menor')).'</b> solicitou seu vínculo como responsável legal no Aura Farming.</p>'
        .'<p>O vínculo não libera câmera ou recursos sociais. A verificação será feita em camadas dentro do próprio Aura: e-mail, código familiar e revisão administrativa. Mesmo depois dela, os recursos do menor continuarão bloqueados até os consentimentos específicos.</p>'
        .'<p><a style="display:inline-block;background:linear-gradient(90deg,#18c8ff,#7144ff);color:#fff;text-decoration:none;padding:14px 20px;border-radius:12px;font-weight:bold" href="'.esc($link).'">ABRIR CONVITE</a></p>'
        .'<p style="font-size:12px;color:#9aa5b9">Este link expira em '.$hours.' horas. ID do menor: '.esc((string)($minor['aura_id']??'')).'</p></div>';
    $sent=enviarEmailSimples($email,$assunto,$html);
    afLogSeguranca($pdo,'guardian_invite_created',20,['invitation_id'=>$id,'email_hash'=>hash('sha256',$email)],$minorUsuarioId);
    return ['id'=>$id,'link'=>$link,'email_enviado'=>$sent,'expira_horas'=>$hours];
}

function afGuardianCancelarConvite(PDO $pdo,int $minorUsuarioId,int $invitationId): void
{
    $st=$pdo->prepare("UPDATE af_guardian_invitations SET status='cancelled',cancelado_em=NOW(),atualizado_em=NOW()
        WHERE id=? AND minor_usuario_id=? AND status='pending'");
    $st->execute([$invitationId,$minorUsuarioId]);
    if($st->rowCount()<1) throw new RuntimeException('Convite não encontrado ou já encerrado.');
}

function afGuardianBuscarConvitePorToken(PDO $pdo,string $rawToken): ?array
{
    if(!preg_match('/^[a-f0-9]{64}$/',$rawToken)) return null;
    $hash=hash('sha256',$rawToken);
    $pdo->prepare("UPDATE af_guardian_invitations SET status='expired',atualizado_em=NOW()
        WHERE token_hash=? AND status='pending' AND expira_em<=NOW()")
        ->execute([$hash]);
    $st=$pdo->prepare('SELECT i.*,m.nome minor_nome,m.aura_id minor_aura_id,m.foto_perfil minor_foto,m.foto_externa minor_foto_externa
        FROM af_guardian_invitations i JOIN af_usuarios m ON m.id=i.minor_usuario_id
        WHERE i.token_hash=? LIMIT 1');
    $st->execute([$hash]);return $st->fetch()?:null;
}

function afGuardianAceitarConvite(PDO $pdo,string $rawToken,int $guardianUsuarioId): array
{
    $invite=afGuardianBuscarConvitePorToken($pdo,$rawToken);
    if(!$invite) throw new RuntimeException('Convite inválido.');
    if($invite['status']!=='pending') throw new RuntimeException($invite['status']==='expired'?'Este convite expirou.':'Este convite já foi encerrado.');
    if((int)$invite['minor_usuario_id']===$guardianUsuarioId) throw new RuntimeException('A conta do menor não pode aceitar o próprio convite.');
    if(!afGuardianUsuarioPodeSerResponsavel($pdo,$guardianUsuarioId)) throw new RuntimeException('Confirme uma idade maior de 18 anos antes de aceitar o vínculo.');
    $st=$pdo->prepare('SELECT nome,email FROM af_usuarios WHERE id=? LIMIT 1');$st->execute([$guardianUsuarioId]);$guardian=$st->fetch();
    if(!$guardian) throw new RuntimeException('Conta do responsável não encontrada.');
    if(strtolower((string)$guardian['email'])!==strtolower((string)$invite['guardian_email'])) {
        throw new RuntimeException('Entre com a conta que utiliza o mesmo e-mail informado no convite.');
    }
    $max=10;
    try{$st=$pdo->prepare("SELECT valor FROM af_configuracoes WHERE chave='guardian_max_dependents'");$st->execute();$max=max(1,(int)($st->fetchColumn()?:10));}catch(Throwable $e){}
    $st=$pdo->prepare("SELECT COUNT(*) FROM af_guardian_minor_links WHERE guardian_usuario_id=? AND status IN ('pending_verification','verified_pending_consent','active')");$st->execute([$guardianUsuarioId]);
    if((int)$st->fetchColumn()>=$max) throw new RuntimeException('Esta conta atingiu o limite de dependentes vinculados.');

    $pdo->beginTransaction();
    try{
        afGuardianGarantirConta($pdo,$guardianUsuarioId,(string)($invite['guardian_telefone']??''),'invitation');
        $pdo->prepare("INSERT INTO af_guardian_minor_links
            (guardian_usuario_id,minor_usuario_id,invitation_id,parentesco,status,aceito_em,criado_em,atualizado_em)
            VALUES (?,?,?,?, 'pending_verification',NOW(),NOW(),NOW())
            ON DUPLICATE KEY UPDATE invitation_id=VALUES(invitation_id),parentesco=VALUES(parentesco),status='pending_verification',aceito_em=NOW(),revogado_em=NULL,motivo_revogacao=NULL,atualizado_em=NOW()")
            ->execute([$guardianUsuarioId,(int)$invite['minor_usuario_id'],(int)$invite['id'],(string)$invite['parentesco']]);
        $pdo->prepare("UPDATE af_guardian_invitations SET status='accepted',aceito_por_usuario_id=?,aceito_em=NOW(),atualizado_em=NOW() WHERE id=?")
            ->execute([$guardianUsuarioId,(int)$invite['id']]);
        $pdo->prepare('INSERT INTO af_age_status_history (usuario_id,status_anterior,status_novo,motivo,actor_usuario_id,dados,criado_em)
            VALUES (?,\'minor_pending_guardian\',\'minor_pending_guardian\',\'responsável vinculado; verificação pendente\',?,?,NOW())')
            ->execute([(int)$invite['minor_usuario_id'],$guardianUsuarioId,json_encode(['guardian_user_id'=>$guardianUsuarioId,'link_status'=>'pending_verification'],JSON_UNESCAPED_UNICODE)]);
        criarNotificacao($pdo,(int)$invite['minor_usuario_id'],'guardian_linked','Responsável vinculado',(string)$guardian['nome'].' aceitou o vínculo. Os recursos sensíveis continuam bloqueados até a verificação e os consentimentos.',['guardian_user_id'=>$guardianUsuarioId]);
        criarNotificacao($pdo,$guardianUsuarioId,'guardian_linked','Vínculo criado','Você foi vinculado como responsável de '.(string)$invite['minor_nome'].'. Agora conclua a confirmação por e-mail, o código familiar e a revisão interna. Os consentimentos específicos virão depois.',['minor_user_id'=>(int)$invite['minor_usuario_id']]);
        $pdo->commit();
    }catch(Throwable $e){if($pdo->inTransaction())$pdo->rollBack();throw $e;}
    afLogSeguranca($pdo,'guardian_invite_accepted',15,['invitation_id'=>(int)$invite['id'],'minor_user_id'=>(int)$invite['minor_usuario_id']],$guardianUsuarioId);
    return afGuardianBuscarVinculoDoMenor($pdo,(int)$invite['minor_usuario_id']) ?: [];
}

function afGuardianDependentes(PDO $pdo,int $guardianUsuarioId): array
{
    $st=$pdo->prepare("SELECT l.*,m.nome,m.username,m.aura_id,m.foto_perfil,m.foto_externa,a.idade_declarada,a.status_idade,p.perfil_privado
        FROM af_guardian_minor_links l
        JOIN af_usuarios m ON m.id=l.minor_usuario_id
        LEFT JOIN af_user_age_profiles a ON a.usuario_id=m.id
        LEFT JOIN af_perfis p ON p.usuario_id=m.id
        WHERE l.guardian_usuario_id=? AND l.status IN ('pending_verification','verified_pending_consent','active')
        ORDER BY l.criado_em DESC");
    $st->execute([$guardianUsuarioId]);return $st->fetchAll();
}

function afGuardianRevogarVinculo(PDO $pdo,int $guardianUsuarioId,int $linkId,string $motivo='Revogado pelo responsável'): void
{
    $st=$pdo->prepare("SELECT * FROM af_guardian_minor_links WHERE id=? AND guardian_usuario_id=? AND status IN ('pending_verification','verified_pending_consent','active') LIMIT 1");
    $st->execute([$linkId,$guardianUsuarioId]);$link=$st->fetch();
    if(!$link) throw new RuntimeException('Vínculo não encontrado.');
    if (function_exists('afConsentRevokeByLink')) {
        afConsentRevokeByLink($pdo,$linkId,$guardianUsuarioId,'Vínculo encerrado pelo responsável');
    }
    $pdo->prepare("UPDATE af_guardian_minor_links SET status='revoked',revogado_em=NOW(),motivo_revogacao=?,atualizado_em=NOW() WHERE id=?")
        ->execute([substr(trim($motivo),0,255),$linkId]);
    $pdo->prepare("UPDATE af_user_age_profiles SET status_idade='minor_pending_guardian',atualizado_em=NOW() WHERE usuario_id=? AND tipo_conta='minor'")
        ->execute([(int)$link['minor_usuario_id']]);
    criarNotificacao($pdo,(int)$link['minor_usuario_id'],'guardian_revoked','Vínculo com responsável encerrado','O vínculo e os consentimentos foram encerrados. Sua conta continua protegida e os recursos sensíveis permanecem bloqueados.');
    afLogSeguranca($pdo,'guardian_link_revoked',25,['link_id'=>$linkId,'minor_user_id'=>(int)$link['minor_usuario_id']],$guardianUsuarioId);
}
