<?php

declare(strict_types=1);

namespace App\Framework\Security;

use InvalidArgumentException;

/**
 * Value object representing a CSRF token.
 *
 * Ensures that CSRF tokens are always valid 64-character hexadecimal strings
 * and provides type safety for CSRF token operations.
 */
final readonly class CsrfToken
{
    private const int TOKEN_LENGTH = 64;

    public function __construct(private string $value)
    {
        $this->validate($value);
    }

    /**
     * Create a CSRF token from a string value.
     */
    public static function fromString(string $value): self
    {
        return new self($value);
    }

    /**
     * Get the token value as a string.
     */
    public function toString(): string
    {
        return $this->value;
    }

    /**
     * Get the token value as a string (magic method).
     */
    public function __toString(): string
    {
        return $this->value;
    }

    /**
     * Check if this token equals another token.
     */
    public function equals(CsrfToken $other): bool
    {
        return hash_equals($this->value, $other->value);
    }

    /**
     * Check if this token equals a string value (time-safe comparison).
     */
    public function equalsString(string $value): bool
    {
        return hash_equals($this->value, $value);
    }

    /**
     * Validate that the token value is a valid CSRF token format.
     */
    private function validate(string $value): void
    {
        if (strlen($value) !== self::TOKEN_LENGTH) {
            throw new InvalidArgumentException(
                sprintf('CSRF token must be exactly %d characters long, got %d', self::TOKEN_LENGTH, strlen($value))
            );
        }

        if (! ctype_xdigit($value)) {
            throw new InvalidArgumentException('CSRF token must be a hexadecimal string');
        }
    }
}
