<?php
/**
 * POST /api/auth/token_refresh.php
 * Body (JSON): { refresh_token }
 *
 * Exchanges a still-valid, unrevoked refresh token for a new short-lived
 * access token. Rotates the refresh token on every use (issues a new one,
 * revokes the old one) - standard refresh-token-rotation practice, so a
 * leaked-and-later-stolen refresh token can only be used once before the
 * legitimate client's next refresh silently invalidates it.
 */

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../includes/response.php';
require_once __DIR__ . '/../includes/auth.php';
require_once __DIR__ . '/../includes/jwt.php';

only_post_allowed();

$input = get_json_input();
$rawToken = trim((string) ($input['refresh_token'] ?? ''));
if ($rawToken === '') {
    send_error('A refresh token is required.', 422);
}

$tokenHash = hash('sha256', $rawToken);
$pdo = Database::connect();

$stmt = $pdo->prepare(
    'SELECT art.id, art.user_id, u.account_type, u.status
     FROM auth_refresh_tokens art
     JOIN users u ON u.id = art.user_id
     WHERE art.token_hash = ? AND art.revoked_at IS NULL AND art.expires_at > NOW()
     LIMIT 1'
);
$stmt->execute([$tokenHash]);
$row = $stmt->fetch();

if (!$row) {
    send_error('This session has expired. Please log in again.', 401);
}
if ($row['status'] !== 'active') {
    send_error('This account is not active. Please contact support.', 403);
}

$pdo->beginTransaction();
try {
    // Revoke the token just used (rotation) ...
    $pdo->prepare('UPDATE auth_refresh_tokens SET revoked_at = NOW(), last_used_at = NOW() WHERE id = ?')
        ->execute([$row['id']]);

    // ... and issue a fresh pair.
    [$accessToken, $newRefreshToken] = issue_token_pair($pdo, (int) $row['user_id'], (string) $row['account_type']);

    $pdo->commit();
} catch (Throwable $e) {
    $pdo->rollBack();
    send_error('Could not refresh session. Please log in again.', 500);
}

send_json(true, 'Session refreshed.', [
    'access_token'  => $accessToken,
    'refresh_token' => $newRefreshToken,
    'expires_in'    => JWT_ACCESS_TTL,
]);
