<?php
// Usage: php scripts/generate_totp.php <BASE32_SECRET> [period] [digits]
// Example: php scripts/generate_totp.php 5MNY3BCK2NKTLMGW6RGP2EMQVNUNCBIB 30 6

function base32_decode_no_padding(string $b32): string {
    $alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    $b32 = strtoupper(trim($b32));
    $buffer = 0; $bitsLeft = 0; $out = '';
    $len = strlen($b32);
    for ($i = 0; $i < $len; $i++) {
        $ch = $b32[$i];
        if ($ch === '=') break; // ignore padding if any
        $pos = strpos($alphabet, $ch);
        if ($pos === false) continue; // skip invalid chars
        $buffer = ($buffer << 5) | $pos;
        $bitsLeft += 5;
        if ($bitsLeft >= 8) {
            $bitsLeft -= 8;
            $out .= chr(($buffer >> $bitsLeft) & 0xFF);
        }
    }
    return $out;
}

function hotp(string $key, int $counter, int $digits = 6): string {
    $binCounter = pack('N*', 0) . pack('N*', $counter);
    $hash = hash_hmac('sha1', $binCounter, $key, true);
    $offset = ord($hash[19]) & 0x0F;
    $truncated = ((ord($hash[$offset]) & 0x7F) << 24) |
        (ord($hash[$offset + 1]) << 16) |
        (ord($hash[$offset + 2]) << 8) |
        (ord($hash[$offset + 3]));
    $code = $truncated % (10 ** $digits);
    return str_pad((string)$code, $digits, '0', STR_PAD_LEFT);
}

function totp(string $key, int $period = 30, int $digits = 6, ?int $now = null): string {
    $now = $now ?? time();
    $counter = (int)floor($now / $period);
    return hotp($key, $counter, $digits);
}

$secretB32 = $argv[1] ?? '';
$period = isset($argv[2]) ? (int)$argv[2] : 30;
$digits = isset($argv[3]) ? (int)$argv[3] : 6;
if ($secretB32 === '') { fwrite(STDERR, "Base32 secret requerido\n"); exit(1); }
if ($period <= 0) $period = 30; if ($digits <= 0) $digits = 6;
$secretBin = base32_decode_no_padding($secretB32);
if ($secretBin === '') { fwrite(STDERR, "Falha ao decodificar Base32\n"); exit(2); }
$code = totp($secretBin, $period, $digits);
echo $code . "\n";