<?php

declare(strict_types=1);

namespace App\Framework\Design\Service;

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

/**
 * Erkennt und analysiert UI-Komponenten
 */
final readonly class ComponentDetector
{
    public function detectBemComponents(array $cssClasses): array
    {
        $components = [];
        $blocks = [];

        foreach ($cssClasses as $cssClass) {
            if ($cssClass->isBemBlock()) {
                $blockName = $cssClass->name;
                if (! isset($blocks[$blockName])) {
                    $blocks[$blockName] = [
                        'block' => $blockName,
                        'elements' => [],
                        'modifiers' => [],
                        'element_modifiers' => [],
                    ];
                }
            }
        }

        // Find elements and modifiers
        foreach ($cssClasses as $cssClass) {
            if ($cssClass->isBemElement()) {
                $block = $cssClass->getBemBlock();
                $element = $cssClass->getBemElement();
                if (isset($blocks[$block]) && $element) {
                    $blocks[$block]['elements'][] = $element;
                }
            }

            if ($cssClass->isBemModifier()) {
                $block = $cssClass->getBemBlock();
                $modifier = $cssClass->getBemModifier();
                if (isset($blocks[$block]) && $modifier) {
                    if ($cssClass->isBemElement()) {
                        $element = $cssClass->getBemElement();
                        if (! isset($blocks[$block]['element_modifiers'][$element])) {
                            $blocks[$block]['element_modifiers'][$element] = [];
                        }
                        $blocks[$block]['element_modifiers'][$element][] = $modifier;
                    } else {
                        $blocks[$block]['modifiers'][] = $modifier;
                    }
                }
            }
        }

        return array_values($blocks);
    }

    public function detectUtilityPatterns(array $cssClasses): array
    {
        $patterns = [];

        foreach ($cssClasses as $cssClass) {
            if ($cssClass->isUtilityClass()) {
                $this->categorizeUtilityClass($cssClass, $patterns);
            }
        }

        return $patterns;
    }

    public function detectStructurePatterns(array $cssClasses): array
    {
        $patterns = [
            'layout' => ['components' => []],
            'form' => ['components' => []],
            'navigation' => ['components' => []],
        ];

        foreach ($cssClasses as $cssClass) {
            $name = $cssClass->name;

            if (in_array($name, ['container', 'row', 'col', 'grid'])) {
                $patterns['layout']['components'][] = $name;
            } elseif (str_starts_with($name, 'form')) {
                $patterns['form']['components'][] = $name;
            } elseif (str_starts_with($name, 'nav')) {
                $patterns['navigation']['components'][] = $name;
            }
        }

        return $patterns;
    }

    public function analyzeResponsivePatterns(array $cssClasses): array
    {
        $breakpoints = [];
        $patterns = [
            'visibility' => [],
            'grid' => [],
            'typography' => [],
        ];

        foreach ($cssClasses as $cssClass) {
            if (preg_match('/(xs|sm|md|lg|xl)/', $cssClass->name, $matches)) {
                $breakpoint = $matches[1];
                if (! in_array($breakpoint, $breakpoints)) {
                    $breakpoints[] = $breakpoint;
                }

                if (str_contains($cssClass->name, 'hidden') || str_contains($cssClass->name, 'visible')) {
                    $patterns['visibility'][] = $cssClass->name;
                } elseif (str_contains($cssClass->name, 'col')) {
                    $patterns['grid'][] = $cssClass->name;
                } elseif (str_contains($cssClass->name, 'text')) {
                    $patterns['typography'][] = $cssClass->name;
                }
            }
        }

        return [
            'breakpoints' => $breakpoints,
            'patterns' => $patterns,
        ];
    }

    public function analyzeComponentComplexity(array $cssClasses): array
    {
        $score = count($cssClasses);

        $level = match(true) {
            $score <= 3 => 'simple',
            $score <= 6 => 'moderate',
            default => 'complex'
        };

        $recommendations = [];
        if ($score > 8) {
            $recommendations[] = 'Consider splitting into smaller components';
        }

        return [
            'score' => $score,
            'level' => $level,
            'recommendations' => $recommendations,
        ];
    }

    public function analyzeAtomicDesignPatterns(array $cssClasses): array
    {
        $atoms = [];
        $molecules = [];
        $organisms = [];

        foreach ($cssClasses as $cssClass) {
            $name = $cssClass->name;

            if (in_array($name, ['btn', 'input', 'label', 'icon'])) {
                $atoms[] = $name;
            } elseif (str_contains($name, 'form') || str_contains($name, 'search') || str_contains($name, 'nav-item')) {
                $molecules[] = $name;
            } elseif (in_array($name, ['header', 'sidebar', 'footer', 'product-grid'])) {
                $organisms[] = $name;
            }
        }

        return [
            'atoms' => $atoms,
            'molecules' => $molecules,
            'organisms' => $organisms,
        ];
    }

    public function validateNamingConventions(array $cssClasses): array
    {
        $valid = [];
        $invalid = [];

        foreach ($cssClasses as $cssClass) {
            $name = $cssClass->name;

            if (preg_match('/^[a-z][a-z0-9-]*[a-z0-9]$/', $name)) {
                $valid[] = $cssClass;
            } else {
                $invalid[] = [
                    'class' => $name,
                    'reason' => $this->getConventionViolation($name),
                ];
            }
        }

        return [
            'valid' => $valid,
            'invalid' => $invalid,
        ];
    }

    public function detectComponentRelationships(array $cssClasses): array
    {
        $relationships = [];

        // Group by BEM blocks
        foreach ($cssClasses as $cssClass) {
            $block = $cssClass->getBemBlock();
            if ($block) {
                if (! isset($relationships[$block])) {
                    $relationships[$block] = [
                        'children' => [],
                        'depth' => 0,
                        'complexity_score' => 0,
                    ];
                }

                if ($cssClass->isBemElement()) {
                    $element = $cssClass->getBemElement();
                    if ($element && ! in_array($element, $relationships[$block]['children'])) {
                        $relationships[$block]['children'][] = $element;
                    }
                }

                $relationships[$block]['complexity_score']++;
            }
        }

        // Calculate depth and complexity
        foreach ($relationships as $block => &$data) {
            $data['depth'] = count($data['children']) > 0 ? 2 : 1;
        }

        return $relationships;
    }

    public function suggestImprovements(array $cssClasses): array
    {
        $suggestions = [];
        $namingInconsistencies = [];
        $bemViolations = [];
        $overlySpecific = [];

        foreach ($cssClasses as $cssClass) {
            $name = $cssClass->name;

            // Check for naming inconsistencies
            if (in_array($name, ['button', 'btn', 'submit-btn'])) {
                $namingInconsistencies[] = $name;
            }

            // Check BEM violations
            if (str_contains($name, 'card-header') && ! str_contains($name, '__')) {
                $bemViolations[] = $name;
            }

            // Check overly specific names
            if (str_word_count($name, 0, '-') > 3) {
                $overlySpecific[] = $name;
            }
        }

        if (! empty($namingInconsistencies)) {
            $suggestions[] = 'Standardize button naming (choose: button, btn)';
        }

        if (! empty($bemViolations)) {
            $suggestions[] = 'Convert card-header to card__header for BEM compliance';
        }

        return [
            'naming_inconsistencies' => $namingInconsistencies,
            'bem_violations' => $bemViolations,
            'overly_specific' => $overlySpecific,
            'suggestions' => $suggestions,
        ];
    }

    public function analyzeComponentReusability(array $cssClasses): array
    {
        $analysis = [];

        foreach ($cssClasses as $cssClass) {
            $name = $cssClass->name;

            // Calculate reusability score
            $score = $this->calculateReusabilityScore($name);
            $variants = $this->countVariants($cssClasses, $name);

            $level = match(true) {
                $score >= 0.8 => 'high',
                $score >= 0.5 => 'medium',
                default => 'low'
            };

            $analysis[$name] = [
                'score' => $score,
                'variants' => $variants,
                'reusability_level' => $level,
            ];
        }

        return $analysis;
    }

    /**
     * Main analysis method used by DesignSystemAnalyzer
     */
    public function detectComponents($parseResult): ComponentDetectionResult
    {
        $bemComponents = $this->detectBemComponents($parseResult->classNames);
        $utilityPatterns = $this->detectUtilityPatterns($parseResult->classNames);
        $structurePatterns = $this->detectStructurePatterns($parseResult->classNames);
        $responsivePatterns = $this->analyzeResponsivePatterns($parseResult->classNames);
        $atomicPatterns = $this->analyzeAtomicDesignPatterns($parseResult->classNames);

        // Convert to ComponentPattern objects
        $bemComponentPatterns = [];
        foreach ($bemComponents as $component) {
            $bemComponentPatterns[] = ComponentPattern::createBem(
                blockName: $component['block'] ?? 'unknown',
                elements: $component['elements'] ?? [],
                modifiers: $component['modifiers'] ?? []
            );
        }

        $utilityComponentPatterns = [];
        foreach ($utilityPatterns as $category => $utilities) {
            if (is_array($utilities)) {
                $utilityComponentPatterns[] = ComponentPattern::createUtility(
                    category: is_string($category) ? $category : 'utilities'
                );
            }
        }

        $traditionalComponentPatterns = [];
        foreach ($structurePatterns as $category => $data) {
            if (isset($data['components']) && ! empty($data['components'])) {
                foreach ($data['components'] as $component) {
                    $traditionalComponentPatterns[] = ComponentPattern::createComponent(
                        name: is_string($component) ? $component : ($component['name'] ?? 'unknown')
                    );
                }
            }
        }

        $totalComponents = count($bemComponentPatterns) + count($utilityComponentPatterns) + count($traditionalComponentPatterns);

        $patternStatistics = [
            'bem_count' => count($bemComponentPatterns),
            'utility_count' => count($utilityComponentPatterns),
            'traditional_count' => count($traditionalComponentPatterns),
            'total_components' => $totalComponents,
            'responsive_patterns' => $responsivePatterns,
            'atomic_patterns' => $atomicPatterns,
        ];

        $recommendations = [];
        if (count($bemComponentPatterns) > 0 && count($traditionalComponentPatterns) > count($bemComponentPatterns)) {
            $recommendations[] = 'Consider refactoring traditional components to BEM methodology';
        }
        if (count($utilityComponentPatterns) < 5 && $totalComponents > 10) {
            $recommendations[] = 'Add utility classes for common patterns like spacing and colors';
        }

        return new ComponentDetectionResult(
            totalComponents: $totalComponents,
            bemComponents: $bemComponentPatterns,
            utilityComponents: $utilityComponentPatterns,
            traditionalComponents: $traditionalComponentPatterns,
            patternStatistics: $patternStatistics,
            recommendations: $recommendations
        );
    }

    private function categorizeUtilityClass(CssClass $cssClass, array &$patterns): void
    {
        $name = $cssClass->name;

        if (str_starts_with($name, 'text-')) {
            $patterns['text-alignment'][] = $name;
        } elseif (str_starts_with($name, 'p-')) {
            $patterns['padding'][] = $name;
        } elseif (str_starts_with($name, 'm-')) {
            $patterns['margin'][] = $name;
        } elseif (str_starts_with($name, 'bg-')) {
            $patterns['background-color'][] = $name;
        } elseif (str_starts_with($name, 'hover:')) {
            $patterns['hover-states'][] = $name;
        }
    }

    private function getConventionViolation(string $name): string
    {
        if (preg_match('/[A-Z]/', $name)) {
            return str_contains($name, '_') ? 'snake_case detected' :
                   (ctype_upper($name[0]) ? 'PascalCase detected' : 'camelCase detected');
        }

        return 'Invalid naming pattern';
    }

    private function calculateReusabilityScore(string $name): float
    {
        // Simple heuristic: shorter, semantic names are more reusable
        if (str_contains($name, 'specific') || str_contains($name, 'page')) {
            return 0.2;
        }

        if (in_array($name, ['btn', 'button', 'card', 'modal'])) {
            return 0.9;
        }

        return 0.6;
    }

    private function countVariants(array $cssClasses, string $baseName): int
    {
        $count = 0;

        foreach ($cssClasses as $cssClass) {
            if (str_starts_with($cssClass->name, $baseName) && $cssClass->name !== $baseName) {
                $count++;
            }
        }

        return $count;
    }
}
