<?php

declare(strict_types=1);

namespace App\Framework\Design\Parser;

use App\Framework\Design\ValueObjects\ComponentPattern;
use App\Framework\Design\ValueObjects\CssClass;

/**
 * Parst CSS-Klassen und erkennt Component-Patterns (BEM, ITCSS, etc.)
 */
final readonly class ClassNameParser
{
    /**
     * Extrahiert CSS-Klassennamen aus Content
     * @return array<int, CssClass>
     */
    public function extractFromContent(string $content): array
    {
        $classNames = [];

        // Alle CSS-Selektoren finden die mit . beginnen
        // Matches escaped colons (\:) but stops at unescaped colons (:)
        preg_match_all('/\.([a-zA-Z][a-zA-Z0-9_-]*(?:\\\\:[a-zA-Z0-9_-]*)*)/m', $content, $matches);

        foreach ($matches[1] as $className) {
            // Unescape CSS class name (e.g., hover\:bg-blue-500 becomes hover:bg-blue-500)
            $unescapedClassName = str_replace('\\:', ':', $className);
            $cssClass = CssClass::fromString($unescapedClassName);
            $classNames[] = $cssClass;
        }

        return $classNames;
    }

    /**
     * Erkennt Component-Patterns in den CSS-Klassen
     * @param array<int, CssClass> $classNames
     * @return array<int, ComponentPattern>
     */
    public function detectPatterns(array $classNames): array
    {
        $patterns = [];

        // BEM Pattern Detection
        $bemComponents = $this->detectBemPatterns($classNames);
        foreach ($bemComponents as $component) {
            $patterns[] = $component;
        }

        // Utility Class Detection
        $utilities = $this->detectUtilityClasses($classNames);
        foreach ($utilities as $utility) {
            $patterns[] = $utility;
        }

        // Component Class Detection (nicht BEM)
        $components = $this->detectComponentClasses($classNames);
        foreach ($components as $component) {
            $patterns[] = $component;
        }

        return $patterns;
    }

    /**
     * Erkennt BEM (Block Element Modifier) Patterns
     */
    private function detectBemPatterns(array $classNames): array
    {
        $bemComponents = [];
        $blocks = [];

        foreach ($classNames as $className => $cssClass) {
            // Block__Element--Modifier Pattern
            if (preg_match('/^([a-z][a-z0-9-]*?)(__[a-z][a-z0-9-]*?)?(--[a-z][a-z0-9-]*?)?$/', $className, $matches)) {
                $block = $matches[1];
                $element = isset($matches[2]) ? substr($matches[2], 2) : null;
                $modifier = isset($matches[3]) ? substr($matches[3], 2) : null;

                if (! isset($blocks[$block])) {
                    $blocks[$block] = [
                        'block' => $block,
                        'elements' => [],
                        'modifiers' => [],
                        'classes' => [],
                    ];
                }

                $blocks[$block]['classes'][] = $cssClass;

                if ($element) {
                    $blocks[$block]['elements'][$element] = $element;
                }

                if ($modifier) {
                    $blocks[$block]['modifiers'][$modifier] = $modifier;
                }
            }
        }

        foreach ($blocks as $block => $data) {
            $bemComponents[] = ComponentPattern::createBem(
                blockName: $block,
                elements: array_values($data['elements']),
                modifiers: array_values($data['modifiers']),
                classes: $data['classes']
            );
        }

        return $bemComponents;
    }

    /**
     * Erkennt Utility Classes (Tailwind-style)
     */
    private function detectUtilityClasses(array $classNames): array
    {
        $utilities = [];

        $utilityPatterns = [
            // Margin/Padding
            '/^[mp][trblxy]?-\d+$/' => 'spacing',
            // Width/Height
            '/^[wh]-\d+$/' => 'sizing',
            // Text utilities
            '/^text-(xs|sm|base|lg|xl|\d+xl|center|left|right)$/' => 'typography',
            // Color utilities
            '/^(text|bg|border)-(red|blue|green|gray|yellow|purple|pink|indigo)-\d+$/' => 'color',
            // Display utilities
            '/^(block|inline|flex|grid|hidden)$/' => 'display',
            // Flexbox utilities
            '/^(justify|items|self)-(start|end|center|between|around)$/' => 'flexbox',
        ];

        foreach ($classNames as $className => $cssClass) {
            foreach ($utilityPatterns as $pattern => $category) {
                if (preg_match($pattern, $className)) {
                    if (! isset($utilities[$category])) {
                        $utilities[$category] = [];
                    }
                    $utilities[$category][] = $cssClass;

                    break;
                }
            }
        }

        $utilityComponents = [];
        foreach ($utilities as $category => $classes) {
            $utilityComponents[] = ComponentPattern::createUtility(
                category: $category,
                classes: $classes
            );
        }

        return $utilityComponents;
    }

    /**
     * Erkennt traditionelle Component Classes
     */
    private function detectComponentClasses(array $classNames): array
    {
        $components = [];

        $componentPatterns = [
            'button' => ['btn', 'button'],
            'card' => ['card'],
            'modal' => ['modal', 'dialog'],
            'form' => ['form', 'input', 'select', 'textarea'],
            'navigation' => ['nav', 'navbar', 'menu'],
            'table' => ['table', 'thead', 'tbody', 'tr', 'td', 'th'],
            'alert' => ['alert', 'message', 'notification'],
            'badge' => ['badge', 'tag', 'chip'],
            'dropdown' => ['dropdown', 'select'],
            'tabs' => ['tab', 'tabs'],
            'accordion' => ['accordion', 'collapse'],
            'breadcrumb' => ['breadcrumb'],
            'pagination' => ['pagination', 'pager'],
        ];

        foreach ($componentPatterns as $componentType => $patterns) {
            $matchingClasses = [];

            foreach ($classNames as $className => $cssClass) {
                foreach ($patterns as $pattern) {
                    if (str_starts_with($className, $pattern) || str_contains($className, $pattern)) {
                        $matchingClasses[] = $cssClass;

                        break;
                    }
                }
            }

            if (! empty($matchingClasses)) {
                $components[] = ComponentPattern::createComponent(
                    name: $componentType,
                    classes: $matchingClasses
                );
            }
        }

        return $components;
    }

    /**
     * Analysiert CSS-Klassen-Konventionen
     */
    public function analyzeConventions(array $classNames): array
    {
        $conventions = [
            'bem_usage' => 0,
            'camelCase_usage' => 0,
            'kebab_case_usage' => 0,
            'snake_case_usage' => 0,
            'total_classes' => count($classNames),
            'violations' => [],
        ];

        foreach ($classNames as $className => $cssClass) {
            // BEM Convention Check
            if (preg_match('/^[a-z][a-z0-9-]*(__[a-z][a-z0-9-]*)?(--[a-z][a-z0-9-]*)?$/', $className)) {
                $conventions['bem_usage']++;
            }

            // camelCase Check
            elseif (preg_match('/^[a-z][a-zA-Z0-9]*$/', $className)) {
                $conventions['camelCase_usage']++;
            }

            // kebab-case Check
            elseif (preg_match('/^[a-z][a-z0-9-]*$/', $className)) {
                $conventions['kebab_case_usage']++;
            }

            // snake_case Check
            elseif (preg_match('/^[a-z][a-z0-9_]*$/', $className)) {
                $conventions['snake_case_usage']++;
            }

            // Convention Violations
            else {
                $conventions['violations'][] = $className;
            }
        }

        return $conventions;
    }
}
