<?php

declare(strict_types=1);

namespace App\Domain\Auth;

/**
 * A parsed `Authorization: Bearer ...` value, after format validation but
 * before DB lookup. Used as a parsing intermediate in
 * TokenAuthenticationMiddleware.
 *
 * `parse()` is permissive about whitespace but strict about format: it
 * rejects malformed prefixes, wrong base32 alphabet, and wrong body length
 * up front so the middleware can return 401 without a DB hit.
 */
final class Token
{
    private const BODY_PATTERN = '/^[A-Z2-7]{32}$/';

    public function __construct(
        public readonly TokenKind $kind,
        public readonly string $raw,
    ) {
    }

    public static function parse(string $raw): ?self
    {
        if (!str_starts_with($raw, 'irdb_')) {
            return null;
        }

        $parts = explode('_', $raw, 3);
        if (count($parts) !== 3) {
            return null;
        }

        [$prefix, $kindCode, $body] = $parts;
        if ($prefix !== 'irdb') {
            return null;
        }

        $kind = TokenKind::fromCode($kindCode);
        if ($kind === null) {
            return null;
        }

        if (preg_match(self::BODY_PATTERN, $body) !== 1) {
            return null;
        }

        return new self($kind, $raw);
    }

    /**
     * The `token_prefix` we persist for ops/log readability. First 8 chars
     * of the raw token — enough to identify a token without revealing it.
     */
    public function prefix(): string
    {
        return substr($this->raw, 0, 8);
    }
}
