<?php

declare(strict_types=1);

namespace App\Framework\Design\ValueObjects;

/**
 * Repräsentiert eine CSS-Regel mit Selektoren und Properties
 */
final readonly class CssRule
{
    /**
     * @param CssSelector[] $selectors
     * @param CssProperty[] $properties
     */
    public function __construct(
        public array $selectors,
        public array $properties
    ) {
    }

    /**
     * Gibt alle Selektor-Strings zurück
     * @return array<int, string>
     */
    public function getSelectorStrings(): array
    {
        return array_map(fn (CssSelector $selector) => $selector->value, $this->selectors);
    }

    /**
     * Gibt alle Property-Namen zurück
     * @return array<int, string>
     */
    public function getPropertyNames(): array
    {
        return array_map(fn (CssProperty $property) => $property->name, $this->properties);
    }

    /**
     * Sucht eine Property nach Namen
     */
    public function getProperty(string $name): ?CssProperty
    {
        foreach ($this->properties as $property) {
            if ($property->name === $name) {
                return $property;
            }
        }

        return null;
    }

    /**
     * Gibt alle Properties einer bestimmten Kategorie zurück
     * @return array<int, CssProperty>
     */
    public function getPropertiesByCategory(CssPropertyCategory $category): array
    {
        return array_filter(
            $this->properties,
            fn (CssProperty $property) => $property->getCategory() === $category
        );
    }

    /**
     * Prüft ob die Regel einen bestimmten Selektor enthält
     */
    public function hasSelector(string $selectorValue): bool
    {
        foreach ($this->selectors as $selector) {
            if ($selector->value === $selectorValue) {
                return true;
            }
        }

        return false;
    }

    /**
     * Prüft ob die Regel eine bestimmte Property enthält
     */
    public function hasProperty(string $propertyName): bool
    {
        return $this->getProperty($propertyName) !== null;
    }

    /**
     * Prüft ob die Regel Custom Properties verwendet
     */
    public function usesCustomProperties(): bool
    {
        foreach ($this->properties as $property) {
            if ($property->usesCustomProperty()) {
                return true;
            }
        }

        return false;
    }

    /**
     * Extrahiert alle Custom Property Referenzen
     */
    public function getCustomPropertyReferences(): array
    {
        $references = [];

        foreach ($this->properties as $property) {
            $propertyRefs = $property->getCustomPropertyReferences();
            $references = array_merge($references, $propertyRefs);
        }

        return array_unique($references);
    }

    /**
     * Gibt die Regel als CSS-String zurück
     */
    public function toCssString(): string
    {
        $selectors = implode(', ', $this->getSelectorStrings());
        $properties = [];

        foreach ($this->properties as $property) {
            $properties[] = "  {$property->name}: {$property->value};";
        }

        $propertiesString = implode("\n", $properties);

        return "$selectors {\n$propertiesString\n}";
    }

    /**
     * Analysiert die Spezifität der Selektoren
     */
    public function getSpecificityAnalysis(): array
    {
        $analysis = [];

        foreach ($this->selectors as $selector) {
            $analysis[] = [
                'selector' => $selector->value,
                'specificity' => $selector->calculateSpecificity(),
                'type' => $selector->getType()->value,
            ];
        }

        return $analysis;
    }

    /**
     * Kategorisiert die Regel basierend auf Selektoren und Properties
     */
    public function categorize(): array
    {
        $selectorTypes = [];
        $propertyCategories = [];

        foreach ($this->selectors as $selector) {
            $selectorTypes[] = $selector->getType()->value;
        }

        foreach ($this->properties as $property) {
            $propertyCategories[] = $property->getCategory()->value;
        }

        return [
            'selector_types' => array_unique($selectorTypes),
            'property_categories' => array_unique($propertyCategories),
            'uses_custom_properties' => $this->usesCustomProperties(),
            'complexity' => $this->calculateComplexity(),
        ];
    }

    private function calculateComplexity(): string
    {
        $selectorCount = count($this->selectors);
        $propertyCount = count($this->properties);
        $totalSpecificity = array_sum(array_map(
            fn (CssSelector $selector) => $selector->calculateSpecificity(),
            $this->selectors
        ));

        $complexityScore = $selectorCount + $propertyCount + ($totalSpecificity / 10);

        return match(true) {
            $complexityScore <= 5 => 'simple',
            $complexityScore <= 15 => 'moderate',
            default => 'complex'
        };
    }
}
