<?php

declare(strict_types=1);

namespace App\Framework\Design\ValueObjects;

/**
 * Repräsentiert einen CSS-Selektor
 */
final readonly class CssSelector
{
    public function __construct(
        public string $value
    ) {
    }

    public static function fromString(string $selector): self
    {
        return new self(trim($selector));
    }

    /**
     * Berechnet die CSS-Spezifität des Selektors
     */
    public function calculateSpecificity(): int
    {
        $specificity = 0;

        // IDs (#id) = 100
        preg_match_all('/#[a-zA-Z][\w-]*/', $this->value, $ids);
        $specificity += count($ids[0]) * 100;

        // Classes (.class), Attributes ([attr]) und Pseudo-Classes (:hover) = 10
        preg_match_all('/\.[a-zA-Z][\w-]*/', $this->value, $classes);
        $specificity += count($classes[0]) * 10;

        preg_match_all('/\[[^\]]*\]/', $this->value, $attributes);
        $specificity += count($attributes[0]) * 10;

        preg_match_all('/:(?!not\(|where\(|is\()[a-zA-Z][\w-]*/', $this->value, $pseudoClasses);
        $specificity += count($pseudoClasses[0]) * 10;

        // Elements (div, span) und Pseudo-Elements (::before) = 1
        $elements = preg_replace('/[#.\[\]:][^#.\[\]\s]*/', '', $this->value);
        preg_match_all('/[a-zA-Z][\w-]*/', $elements, $elementMatches);
        $specificity += count($elementMatches[0]);

        return $specificity;
    }

    /**
     * Analysiert den Selektor-Typ
     */
    public function getType(): CssSelectorType
    {
        if (str_starts_with($this->value, '.')) {
            return CssSelectorType::CLASS_SELECTOR;
        }

        if (str_starts_with($this->value, '#')) {
            return CssSelectorType::ID;
        }

        if (str_contains($this->value, '[')) {
            return CssSelectorType::ATTRIBUTE;
        }

        if (str_contains($this->value, ':')) {
            return CssSelectorType::PSEUDO;
        }

        if (preg_match('/^[a-zA-Z][\w-]*$/', $this->value)) {
            return CssSelectorType::ELEMENT;
        }

        return CssSelectorType::COMPLEX;
    }

    /**
     * Extrahiert alle CSS-Klassennamen aus dem Selektor
     * @return array<int, string>
     */
    public function extractClasses(): array
    {
        preg_match_all('/\.([a-zA-Z][\w-]*)/', $this->value, $matches);

        return $matches[1] ?? [];
    }

    /**
     * Extrahiert alle IDs aus dem Selektor
     * @return array<int, string>
     */
    public function extractIds(): array
    {
        preg_match_all('/#([a-zA-Z][\w-]*)/', $this->value, $matches);

        return $matches[1] ?? [];
    }

    /**
     * Extrahiert alle Element-Namen aus dem Selektor
     * @return array<int, string>
     */
    public function extractElements(): array
    {
        $cleaned = preg_replace('/[#.\[\]:][^#.\[\]\s]*/', '', $this->value);
        preg_match_all('/[a-zA-Z][\w-]*/', $cleaned, $matches);

        return array_filter($matches[0], fn ($element) => ! empty($element));
    }

    public function toString(): string
    {
        return $this->value;
    }
}
