<?php

declare(strict_types=1);

namespace App\Framework\Tokenizer\ValueObjects;

/**
 * Represents a single token with full context
 */
final readonly class Token
{
    public function __construct(
        public TokenType $type,
        public string $value,
        public int $line,
        public int $position,
        public int $id,
        public TokenContext $context
    ) {
    }

    /**
     * Check if token is a specific PHP token type
     */
    public function is(int|array $tokenId): bool
    {
        if (is_array($tokenId)) {
            return in_array($this->id, $tokenId, true);
        }

        return $this->id === $tokenId;
    }

    /**
     * Check if token is structural (class, function, namespace, etc.)
     */
    public function isStructural(): bool
    {
        return $this->is([
            T_CLASS, T_INTERFACE, T_TRAIT, T_ENUM,
            T_FUNCTION, T_NAMESPACE, T_USE,
            T_EXTENDS, T_IMPLEMENTS,
            T_PUBLIC, T_PROTECTED, T_PRIVATE,
            T_STATIC, T_FINAL, T_ABSTRACT, T_READONLY,
        ]);
    }

    /**
     * Check if token is an attribute
     */
    public function isAttribute(): bool
    {
        return $this->is(T_ATTRIBUTE) ||
               ($this->context->isInAttribute && $this->is(T_STRING));
    }

    /**
     * Check if token is a doc comment
     */
    public function isDocComment(): bool
    {
        return $this->is(T_DOC_COMMENT);
    }

    /**
     * Check if token is a keyword
     */
    public function isKeyword(): bool
    {
        return $this->type === TokenType::KEYWORD;
    }

    /**
     * Check if token is an identifier (class name, function name, etc.)
     */
    public function isIdentifier(): bool
    {
        return in_array($this->type, [
            TokenType::CLASS_NAME,
            TokenType::FUNCTION_NAME,
            TokenType::METHOD_NAME,
            TokenType::PROPERTY_NAME,
            TokenType::CONSTANT_NAME,
        ], true);
    }

    /**
     * Get token length
     */
    public function getLength(): int
    {
        return strlen($this->value);
    }

    /**
     * Get end position
     */
    public function getEndPosition(): int
    {
        return $this->position + $this->getLength();
    }

    /**
     * Check if this token contains a specific position
     */
    public function containsPosition(int $position): bool
    {
        return $position >= $this->position && $position < $this->getEndPosition();
    }

    /**
     * Get a clean version of the value (trimmed, no quotes, etc.)
     */
    public function getCleanValue(): string
    {
        return match($this->type) {
            TokenType::STRING_LITERAL => trim($this->value, '"\''),
            TokenType::DOC_COMMENT => trim($this->value, '/*'),
            default => trim($this->value)
        };
    }
}
