<?php

declare(strict_types=1);

namespace App\Framework\Design\ValueObjects;

use App\Framework\Filesystem\ValueObjects\FilePath;

/**
 * Ergebnis des CSS-Parsing-Prozesses
 */
final readonly class CssParseResult
{
    /**
     * @param CssRule[] $rules
     * @param DesignToken[] $customProperties
     * @param CssClassName[] $classNames
     */
    public function __construct(
        public ?FilePath $sourceFile,
        public array $rules,
        public array $customProperties,
        public array $classNames,
        public string $rawContent
    ) {
    }

    /**
     * Gibt alle gefundenen Selektoren zurück
     * @return CssSelector[]
     */
    public function getAllSelectors(): array
    {
        $selectors = [];

        foreach ($this->rules as $rule) {
            foreach ($rule->selectors as $selector) {
                $selectors[] = $selector;
            }
        }

        return $selectors;
    }

    /**
     * Gibt alle gefundenen Properties zurück
     * @return CssProperty[]
     */
    public function getAllProperties(): array
    {
        $properties = [];

        foreach ($this->rules as $rule) {
            foreach ($rule->properties as $property) {
                $properties[] = $property;
            }
        }

        return $properties;
    }

    /**
     * Filtert Regeln nach Selektor-Typ
     */
    public function getRulesBySelectorType(CssSelectorType $type): array
    {
        $matchingRules = [];

        foreach ($this->rules as $rule) {
            foreach ($rule->selectors as $selector) {
                if ($selector->getType() === $type) {
                    $matchingRules[] = $rule;

                    break;
                }
            }
        }

        return $matchingRules;
    }

    /**
     * Filtert Properties nach Kategorie
     */
    public function getPropertiesByCategory(CssPropertyCategory $category): array
    {
        return array_filter(
            $this->getAllProperties(),
            fn (CssProperty $property) => $property->getCategory() === $category
        );
    }

    /**
     * Filtert Custom Properties nach Typ
     */
    public function getDesignTokensByType(DesignTokenType $type): array
    {
        return array_filter(
            $this->customProperties,
            fn (DesignToken $token) => $token->type === $type
        );
    }

    /**
     * Filtert CSS-Klassen nach Pattern
     */
    public function getClassNamesByPattern(string $pattern): array
    {
        return array_filter(
            $this->classNames,
            fn (CssClassName $className) => str_contains($className->name, $pattern)
        );
    }

    /**
     * Gibt alle BEM-Klassen zurück
     */
    public function getBemClasses(): array
    {
        return array_filter(
            $this->classNames,
            fn (CssClassName $className) =>
                $className->isBemBlock() ||
                $className->isBemElement() ||
                $className->isBemModifier()
        );
    }

    /**
     * Gibt alle Utility-Klassen zurück
     */
    public function getUtilityClasses(): array
    {
        return array_filter(
            $this->classNames,
            fn (CssClassName $className) => $className->isUtilityClass()
        );
    }

    /**
     * Analysiert verwendete Farben
     */
    public function getColorAnalysis(): array
    {
        $colors = [];
        $colorProperties = $this->getPropertiesByCategory(CssPropertyCategory::COLOR);

        foreach ($colorProperties as $property) {
            $color = $property->toColor();
            if ($color) {
                $colors[] = [
                    'property' => $property->name,
                    'color' => $color,
                    'format' => $color->format->value,
                    'hex' => $color->toHex(),
                ];
            }
        }

        return $colors;
    }

    /**
     * Analysiert Naming-Konventionen
     */
    public function getNamingConventionAnalysis(): array
    {
        $conventions = [
            'bem' => 0,
            'camelCase' => 0,
            'kebab-case' => 0,
            'snake_case' => 0,
            'other' => 0,
            'violations' => [],
        ];

        foreach ($this->classNames as $className) {
            $convention = $className->getNamingConvention();

            if (isset($conventions[$convention])) {
                $conventions[$convention]++;
            } else {
                $conventions['other']++;
                $conventions['violations'][] = $className->name;
            }
        }

        $conventions['total_classes'] = count($this->classNames);
        $conventions['dominant_convention'] = $this->getDominantConvention($conventions);

        return $conventions;
    }

    /**
     * Statistiken über die geparsten Daten
     */
    public function getStatistics(): array
    {
        return [
            'source_file' => $this->sourceFile?->toString(),
            'total_rules' => count($this->rules),
            'total_selectors' => count($this->getAllSelectors()),
            'total_properties' => count($this->getAllProperties()),
            'design_tokens' => count($this->customProperties),
            'class_names' => count($this->classNames),
            'content_size_bytes' => strlen($this->rawContent),
            'selector_types' => $this->getSelectorTypeStats(),
            'property_categories' => $this->getPropertyCategoryStats(),
            'token_types' => $this->getTokenTypeStats(),
        ];
    }

    private function getDominantConvention(array $conventions): string
    {
        $max = 0;
        $dominant = 'mixed';

        foreach (['bem', 'camelCase', 'kebab-case', 'snake_case'] as $convention) {
            if ($conventions[$convention] > $max) {
                $max = $conventions[$convention];
                $dominant = $convention;
            }
        }

        return $dominant;
    }

    private function getSelectorTypeStats(): array
    {
        $stats = [];

        foreach ($this->getAllSelectors() as $selector) {
            $type = $selector->getType()->value;
            $stats[$type] = ($stats[$type] ?? 0) + 1;
        }

        return $stats;
    }

    private function getPropertyCategoryStats(): array
    {
        $stats = [];

        foreach ($this->getAllProperties() as $property) {
            $category = $property->getCategory()->value;
            $stats[$category] = ($stats[$category] ?? 0) + 1;
        }

        return $stats;
    }

    private function getTokenTypeStats(): array
    {
        $stats = [];

        foreach ($this->customProperties as $token) {
            $type = $token->type->value;
            $stats[$type] = ($stats[$type] ?? 0) + 1;
        }

        return $stats;
    }
}
