<?php

namespace App\Framework\SyntaxHighlighter;

final class TokenMapper {
    private array $mapping = [];

    public function __construct() {
        $this->initializeDefaultMapping();
    }

    private function initializeDefaultMapping(): void {
        $this->mapping = [
            // Schlüsselwörter
            T_ABSTRACT => TokenType::KEYWORD,
            T_ARRAY => TokenType::KEYWORD,
            T_AS => TokenType::KEYWORD,
            T_BREAK => TokenType::KEYWORD,
            T_CASE => TokenType::KEYWORD,
            T_CATCH => TokenType::KEYWORD,
            T_CLASS => TokenType::KEYWORD,
            T_CLONE => TokenType::KEYWORD,
            T_CONST => TokenType::KEYWORD,
            T_CONTINUE => TokenType::KEYWORD,
            T_DEFAULT => TokenType::KEYWORD,
            T_DO => TokenType::KEYWORD,
            T_ECHO => TokenType::KEYWORD,
            T_ELSE => TokenType::KEYWORD,
            T_ELSEIF => TokenType::KEYWORD,
            T_EMPTY => TokenType::KEYWORD,
            T_EXTENDS => TokenType::KEYWORD,
            T_FINAL => TokenType::KEYWORD,
            T_FINALLY => TokenType::KEYWORD,
            T_FOR => TokenType::KEYWORD,
            T_FOREACH => TokenType::KEYWORD,
            T_FUNCTION => TokenType::KEYWORD,
            T_IF => TokenType::KEYWORD,
            T_IMPLEMENTS => TokenType::KEYWORD,
            T_INCLUDE => TokenType::KEYWORD,
            T_INCLUDE_ONCE => TokenType::KEYWORD,
            T_INSTANCEOF => TokenType::KEYWORD,
            T_INTERFACE => TokenType::KEYWORD,
            T_ISSET => TokenType::KEYWORD,
            T_NAMESPACE => TokenType::KEYWORD,
            T_NEW => TokenType::KEYWORD,
            T_PRIVATE => TokenType::KEYWORD,
            T_PROTECTED => TokenType::KEYWORD,
            T_PUBLIC => TokenType::KEYWORD,
            T_REQUIRE => TokenType::KEYWORD,
            T_REQUIRE_ONCE => TokenType::KEYWORD,
            T_RETURN => TokenType::KEYWORD,
            T_STATIC => TokenType::KEYWORD,
            T_SWITCH => TokenType::KEYWORD,
            T_THROW => TokenType::KEYWORD,
            T_TRY => TokenType::KEYWORD,
            T_UNSET => TokenType::KEYWORD,
            T_USE => TokenType::KEYWORD,
            T_VAR => TokenType::KEYWORD,
            T_WHILE => TokenType::KEYWORD,
            T_YIELD => TokenType::KEYWORD,

            // Variablen und Strings
            T_VARIABLE => TokenType::VARIABLE,
            T_CONSTANT_ENCAPSED_STRING => TokenType::STRING,
            T_ENCAPSED_AND_WHITESPACE => TokenType::STRING,
            T_STRING => TokenType::IDENTIFIER,

            // Zahlen
            T_LNUMBER => TokenType::NUMBER,
            T_DNUMBER => TokenType::NUMBER,

            // Kommentare
            T_COMMENT => TokenType::COMMENT,
            T_DOC_COMMENT => TokenType::DOC_COMMENT,

            // PHP Tags
            T_OPEN_TAG => TokenType::PHP_TAG,
            T_OPEN_TAG_WITH_ECHO => TokenType::PHP_TAG,
            T_CLOSE_TAG => TokenType::PHP_TAG,

            // Operatoren
            T_DOUBLE_ARROW => TokenType::OPERATOR,
            T_OBJECT_OPERATOR => TokenType::OPERATOR,
            T_PAAMAYIM_NEKUDOTAYIM => TokenType::OPERATOR,
            T_BOOLEAN_AND => TokenType::OPERATOR,
            T_BOOLEAN_OR => TokenType::OPERATOR,
            T_IS_EQUAL => TokenType::OPERATOR,
            T_IS_NOT_EQUAL => TokenType::OPERATOR,
            T_IS_IDENTICAL => TokenType::OPERATOR,
            T_IS_NOT_IDENTICAL => TokenType::OPERATOR,
            T_IS_SMALLER_OR_EQUAL => TokenType::OPERATOR,
            T_IS_GREATER_OR_EQUAL => TokenType::OPERATOR,
            T_SPACESHIP => TokenType::OPERATOR,
            T_COALESCE => TokenType::OPERATOR,

            // Whitespace
            T_WHITESPACE => TokenType::WHITESPACE,
        ];
    }

    public function getTokenType(int $phpToken): TokenType {
        return $this->mapping[$phpToken] ?? TokenType::DEFAULT;
    }

    public function addMapping(int $phpToken, TokenType $tokenType): self {
        $this->mapping[$phpToken] = $tokenType;
        return $this;
    }

    public function removeMapping(int $phpToken): self {
        unset($this->mapping[$phpToken]);
        return $this;
    }

    public function hasMapping(int $phpToken): bool {
        return isset($this->mapping[$phpToken]);
    }

    public function getAllMappings(): array {
        return $this->mapping;
    }

    public function setMappings(array $mappings): self {
        $this->mapping = $mappings;
        return $this;
    }

    public function mergeMappings(array $additionalMappings): self {
        $this->mapping = array_merge($this->mapping, $additionalMappings);
        return $this;
    }
}
