<?php

namespace KeyLair;

/**
 * Server-to-server bearer tokens for external tools (e.g. Sendy) calling
 * into the API under public/api/ -- unrelated to admin session auth. Only
 * a token's hash is ever stored; the raw value is returned once, at
 * creation time, same as a password (create() is the only place it's ever
 * visible again).
 */
class ApiToken
{
    public static function create(int $adminUserId, string $label): array
    {
        $raw = 'kl_' . Helpers::randomToken(32);
        $pdo = Database::connection();
        $stmt = $pdo->prepare('INSERT INTO api_tokens (label, token_hash, created_by, created_at) VALUES (?, ?, ?, NOW())');
        $stmt->execute([trim($label) !== '' ? trim($label) : 'Unnamed token', hash('sha256', $raw), $adminUserId]);
        return ['id' => (int) $pdo->lastInsertId(), 'raw' => $raw];
    }

    /** Verifies a raw bearer token against every non-revoked hash, bumps last_used_at, and returns the matching row (or null). */
    public static function verify(string $raw): ?array
    {
        $pdo = Database::connection();
        $stmt = $pdo->prepare('SELECT * FROM api_tokens WHERE token_hash = :hash AND revoked_at IS NULL');
        $stmt->execute(['hash' => hash('sha256', $raw)]);
        $token = $stmt->fetch();
        if (!$token) {
            return null;
        }
        $pdo->prepare('UPDATE api_tokens SET last_used_at = NOW() WHERE id = :id')->execute(['id' => $token['id']]);
        return $token;
    }

    public static function revoke(int $id): void
    {
        Database::connection()->prepare('UPDATE api_tokens SET revoked_at = NOW() WHERE id = :id')->execute(['id' => $id]);
    }
}
