<?php
/**
 * webauthn-login-verify.php — Passkey login (2nd factor): step 2
 *
 * Receives the browser's navigator.credentials.get() response, looks up
 * the credential by ID, verifies it against the challenge stored by
 * webauthn-login-options.php and the credential's stored public key, and
 * — on success — completes the login by setting the SAME session state
 * index.php's password-only path sets, then clears the pending-2FA flag.
 */
require_once __DIR__ . '/../includes/functions.php';

header('Content-Type: application/json; charset=UTF-8');

if (!isset($_SESSION['pending_2fa_user_id'])) {
    http_response_code(403);
    echo json_encode(['success' => false, 'error' => 'No pending login.']);
    exit;
}

$input = json_decode((string) file_get_contents('php://input'), true);
if (!is_array($input) || !verify_token((string) ($input['csrf_token'] ?? ''))) {
    http_response_code(403);
    echo json_encode(['success' => false, 'error' => 'Invalid request.']);
    exit;
}

$challengeB64 = $_SESSION['webauthn_login_challenge'] ?? null;
if ($challengeB64 === null) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => 'No pending challenge. Please try again.']);
    exit;
}

$userId = (int) $_SESSION['pending_2fa_user_id'];

$rawId = base64_decode((string) ($input['id'] ?? ''), true);
$clientDataJSON = base64_decode((string) ($input['clientDataJSON'] ?? ''), true);
$authenticatorData = base64_decode((string) ($input['authenticatorData'] ?? ''), true);
$signature = base64_decode((string) ($input['signature'] ?? ''), true);

if ($rawId === false || $clientDataJSON === false || $authenticatorData === false || $signature === false) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => 'Malformed login response.']);
    exit;
}

$credentialIdHex = bin2hex($rawId);
$credentialRows = $db->select(
    'webauthn_credentials',
    '*',
    'user_id = :uid AND credential_id = :cid',
    '',
    [':uid' => $userId, ':cid' => $credentialIdHex]
);

if (empty($credentialRows)) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => 'Unrecognized passkey.']);
    exit;
}
$credentialRow = $credentialRows[0];

try {
    $webAuthn->processGet(
        $clientDataJSON,
        $authenticatorData,
        $signature,
        $credentialRow['public_key'],
        base64_decode($challengeB64, true),
        (int) $credentialRow['sign_count'],
        requireUserVerification: false,
        requireUserPresent: true
    );

    // Update the stored signature counter (cloned-authenticator detection
    // for future logins) and last-used timestamp.
    $newSignCount = $webAuthn->getSignatureCounter();
    $db->update(
        'webauthn_credentials',
        [
            'sign_count' => $newSignCount ?? $credentialRow['sign_count'],
            'last_used_at' => date('Y-m-d H:i:s'),
        ],
        'id = :id',
        [':id' => $credentialRow['id']]
    );

    // Complete the login — same session state index.php's password-only
    // path sets on success.
    $userRow = $db->select('user', '*', 'id = :id', '', [':id' => $userId]);
    if (empty($userRow)) {
        throw new \RuntimeException('User record not found.');
    }

    session_regenerate_id(true);
    $_SESSION['loggedin'] = true;
    $_SESSION['name'] = $userRow[0]['username'];
    $_SESSION['login_time'] = time();
    unset($_SESSION['pending_2fa_user_id'], $_SESSION['webauthn_login_challenge']);

    echo json_encode(['success' => true, 'redirect' => 'main.php']);
} catch (\lbuchs\WebAuthn\WebAuthnException $e) {
    http_response_code(400);
    echo json_encode(['success' => false, 'error' => 'Verification failed: ' . $e->getMessage()]);
} catch (\Throwable $e) {
    // See webauthn-register-verify.php's matching catch-all for why this
    // exists: an uncaught PHP Error/RuntimeException here would otherwise
    // print as HTML, breaking the browser's JSON.parse() of the response.
    error_log('webauthn-login-verify: unexpected error: ' . $e->getMessage());
    http_response_code(500);
    echo json_encode(['success' => false, 'error' => 'An unexpected error occurred during verification.']);
}
