<?php

declare(strict_types=1);

namespace Plugin\tnt_mcp\src\Mcp\Log;

use RuntimeException;

/**
 * The opaque page marker: the `(timestamp, id)` of the last row already delivered.
 *
 * Keyset, not offset, and the pair rather than the timestamp alone — `tjtllog` writes many rows
 * per second, so a timestamp-only cursor would either skip or repeat everything sharing the last
 * second. Base64 so no caller is tempted to build one by hand; the payload is not a secret and is
 * not signed, because a forged cursor can only move the caller's own window inside a result set it
 * is already allowed to read.
 */
final class LogCursor
{
    /** @param string $ts MySQL datetime, exactly as the time column stores it */
    public function __construct(
        public readonly string $ts,
        public readonly int $id,
    ) {
    }

    public function encode(): string
    {
        return \base64_encode((string)\json_encode(['ts' => $this->ts, 'id' => $this->id]));
    }

    /** @throws RuntimeException on anything that is not one of our own cursors */
    public static function decode(string $raw): self
    {
        $json = \base64_decode(\trim($raw), true);
        $data = $json === false ? null : \json_decode($json, true);
        if (!\is_array($data) || !\is_string($data['ts'] ?? null) || !\is_int($data['id'] ?? null)) {
            throw new RuntimeException(
                'read_logs: "cursor" is not a cursor this tool issued. '
                . 'Pass back the nextCursor value verbatim, or omit it to start from the newest entry.'
            );
        }

        return new self($data['ts'], $data['id']);
    }
}
