<?php

declare(strict_types=1);

use App\Framework\Design\Service\ConventionChecker;
use App\Framework\Design\ValueObjects\CssClass;
use App\Framework\Design\ValueObjects\CustomProperty;

describe('ConventionChecker', function () {

    beforeEach(function () {
        $this->checker = new ConventionChecker();
    });

    it('validates BEM naming conventions', function () {
        $cssClasses = [
            new CssClass('button'),                    // Valid: Block
            new CssClass('button__icon'),              // Valid: Element
            new CssClass('button--primary'),           // Valid: Modifier
            new CssClass('button__icon--large'),       // Valid: Element modifier
            new CssClass('button_icon'),               // Invalid: underscore instead of double
            new CssClass('button--primary--large'),   // Invalid: double modifier
            new CssClass('BUTTON'),                    // Invalid: uppercase
            new CssClass('button__'),                  // Invalid: empty element
            new CssClass('button--'),                  // Invalid: empty modifier
        ];

        $validation = $this->checker->validateBemNaming($cssClasses);

        expect($validation['valid'])->toHaveCount(4);
        expect($validation['invalid'])->toHaveCount(5);

        $invalidClasses = array_column($validation['invalid'], 'class');
        expect($invalidClasses)->toContain('button_icon');
        expect($invalidClasses)->toContain('button--primary--large');
        expect($invalidClasses)->toContain('BUTTON');
    });

    it('checks kebab-case consistency', function () {
        $cssClasses = [
            new CssClass('nav-menu'),              // Valid
            new CssClass('user-profile'),          // Valid
            new CssClass('search-input'),          // Valid
            new CssClass('camelCase'),             // Invalid
            new CssClass('PascalCase'),            // Invalid
            new CssClass('snake_case'),            // Invalid
            new CssClass('SCREAMING_CASE'),        // Invalid
            new CssClass('123-invalid'),           // Invalid: starts with number
        ];

        $validation = $this->checker->validateKebabCase($cssClasses);

        expect($validation['valid'])->toHaveCount(3);
        expect($validation['invalid'])->toHaveCount(5);

        $violations = array_column($validation['invalid'], 'violation');
        expect($violations)->toContain('camelCase detected');
        expect($violations)->toContain('PascalCase detected');
        expect($violations)->toContain('snake_case detected');
    });

    it('validates custom property naming', function () {
        $customProperties = [
            new CustomProperty('primary-color', '#3b82f6'),        // Valid
            new CustomProperty('text-base', '16px'),               // Valid
            new CustomProperty('spacing-md', '1rem'),              // Valid
            new CustomProperty('fontSize', '18px'),                // Invalid: camelCase
            new CustomProperty('TEXT_SIZE', '20px'),               // Invalid: UPPERCASE
            new CustomProperty('border_width', '1px'),             // Invalid: snake_case
            new CustomProperty('123-invalid', '1px'),              // Invalid: starts with number
            new CustomProperty('--invalid', 'value'),              // Invalid: starts with --
        ];

        $validation = $this->checker->validateCustomPropertyNaming($customProperties);

        expect($validation['valid'])->toHaveCount(3);
        expect($validation['invalid'])->toHaveCount(5);

        $invalidNames = array_column($validation['invalid'], 'property');
        expect($invalidNames)->toContain('fontSize');
        expect($invalidNames)->toContain('TEXT_SIZE');
        expect($invalidNames)->toContain('border_width');
    });

    it('checks semantic naming conventions', function () {
        $cssClasses = [
            // Good semantic names
            new CssClass('header'),
            new CssClass('navigation'),
            new CssClass('content'),
            new CssClass('sidebar'),
            new CssClass('footer'),

            // Poor semantic names
            new CssClass('red-text'),              // Presentational
            new CssClass('big-box'),               // Presentational
            new CssClass('left-column'),           // Positional
            new CssClass('div1'),                  // Generic
            new CssClass('thing'),                 // Vague
        ];

        $validation = $this->checker->validateSemanticNaming($cssClasses);

        expect($validation['semantic'])->toHaveCount(5);
        expect($validation['presentational'])->toHaveCount(2);
        expect($validation['positional'])->toHaveCount(1);
        expect($validation['generic'])->toHaveCount(1);
        expect($validation['vague'])->toHaveCount(1);

        expect($validation['score'])->toBeCloseTo(0.5, 1); // 5/10 are semantic
    });

    it('validates design token naming patterns', function () {
        $customProperties = [
            // Good design system patterns
            new CustomProperty('color-primary-500', '#3b82f6'),
            new CustomProperty('spacing-xs', '0.25rem'),
            new CustomProperty('font-size-lg', '1.125rem'),
            new CustomProperty('border-radius-md', '0.375rem'),

            // Inconsistent patterns
            new CustomProperty('primary', '#3b82f6'),          // Too generic
            new CustomProperty('blueColor', '#1d4ed8'),        // camelCase
            new CustomProperty('spacing_small', '0.5rem'),     // snake_case
            new CustomProperty('very-very-long-property-name-that-is-too-verbose', '1px'),
        ];

        $validation = $this->checker->validateDesignTokenNaming($customProperties);

        expect($validation['consistent'])->toHaveCount(4);
        expect($validation['inconsistent'])->toHaveCount(4);

        $issues = array_column($validation['inconsistent'], 'issue');
        expect($issues)->toContain('Too generic');
        expect($issues)->toContain('Wrong case format');
        expect($issues)->toContain('Too verbose');
    });

    it('checks accessibility naming conventions', function () {
        $cssClasses = [
            // Good accessibility-focused names
            new CssClass('sr-only'),               // Screen reader only
            new CssClass('visually-hidden'),       // Visually hidden
            new CssClass('skip-link'),             // Skip navigation
            new CssClass('focus-visible'),         // Focus indicator

            // Potentially problematic
            new CssClass('hidden'),                // Too generic
            new CssClass('invisible'),             // Unclear intent
            new CssClass('no-display'),            // Unclear semantics
        ];

        $validation = $this->checker->validateAccessibilityNaming($cssClasses);

        expect($validation['accessibility_friendly'])->toHaveCount(4);
        expect($validation['potentially_problematic'])->toHaveCount(3);

        $recommendations = $validation['recommendations'];
        expect($recommendations)->toContain('Consider "visually-hidden" instead of "hidden"');
        expect($recommendations)->toContain('Consider "sr-only" instead of "invisible"');
    });

    it('validates component naming hierarchy', function () {
        $cssClasses = [
            // Good hierarchical naming
            new CssClass('card'),
            new CssClass('card__header'),
            new CssClass('card__title'),
            new CssClass('card__body'),
            new CssClass('card__footer'),

            // Poor hierarchical naming
            new CssClass('cardHeader'),            // camelCase, no hierarchy
            new CssClass('card-title-text'),       // Flat, not hierarchical
            new CssClass('header'),                // Too generic when card__header exists
        ];

        $validation = $this->checker->validateComponentHierarchy($cssClasses);

        expect($validation['well_structured'])->toHaveCount(5);
        expect($validation['poorly_structured'])->toHaveCount(3);

        $cardHierarchy = $validation['hierarchies']['card'];
        expect($cardHierarchy['elements'])->toContain('header');
        expect($cardHierarchy['elements'])->toContain('title');
        expect($cardHierarchy['depth'])->toBe(2);
    });

    it('analyzes naming consistency across project', function () {
        $cssClasses = [
            // Consistent button pattern
            new CssClass('btn'),
            new CssClass('btn--primary'),
            new CssClass('btn--secondary'),

            // Inconsistent button pattern
            new CssClass('button'),
            new CssClass('submit-button'),

            // Consistent form pattern
            new CssClass('form'),
            new CssClass('form__group'),
            new CssClass('form__label'),
            new CssClass('form__input'),
        ];

        $consistency = $this->checker->analyzeNamingConsistency($cssClasses);

        expect($consistency['overall_score'])->toBeBetween(0.6, 0.8);
        expect($consistency['patterns']['btn']['consistency'])->toBe(1.0);
        expect($consistency['patterns']['button']['consistency'])->toBeLessThan(1.0);
        expect($consistency['inconsistencies'])->toContain('Mixed button naming: btn, button');
    });

    it('suggests naming improvements', function () {
        $cssClasses = [
            new CssClass('redText'),               // camelCase + presentational
            new CssClass('big_button'),            // snake_case
            new CssClass('NAVIGATION'),            // UPPERCASE
            new CssClass('div123'),                // Generic + number
            new CssClass('thing'),                 // Vague
        ];

        $suggestions = $this->checker->suggestNamingImprovements($cssClasses);

        expect($suggestions)->toHaveCount(5);

        $redTextSuggestion = collect($suggestions)->firstWhere('original', 'redText');
        expect($redTextSuggestion['improved'])->toBe('error-text');
        expect($redTextSuggestion['reasons'])->toContain('Convert to kebab-case');
        expect($redTextSuggestion['reasons'])->toContain('Use semantic naming');

        $bigButtonSuggestion = collect($suggestions)->firstWhere('original', 'big_button');
        expect($bigButtonSuggestion['improved'])->toBe('button--large');
        expect($bigButtonSuggestion['reasons'])->toContain('Convert to kebab-case');
        expect($bigButtonSuggestion['reasons'])->toContain('Use BEM modifier pattern');
    });

    it('validates framework-specific conventions', function () {
        // Test Bootstrap-like conventions
        $bootstrapClasses = [
            new CssClass('btn'),
            new CssClass('btn-primary'),
            new CssClass('btn-lg'),
            new CssClass('container'),
            new CssClass('row'),
            new CssClass('col-md-6'),
        ];

        $bootstrapValidation = $this->checker->validateFrameworkConventions($bootstrapClasses, 'bootstrap');
        expect($bootstrapValidation['compliant'])->toHaveCount(6);

        // Test Tailwind-like conventions
        $tailwindClasses = [
            new CssClass('text-center'),
            new CssClass('bg-blue-500'),
            new CssClass('p-4'),
            new CssClass('hover:bg-blue-600'),
            new CssClass('sm:text-left'),
        ];

        $tailwindValidation = $this->checker->validateFrameworkConventions($tailwindClasses, 'tailwind');
        expect($tailwindValidation['compliant'])->toHaveCount(5);

        // Test BEM conventions
        $bemClasses = [
            new CssClass('block'),
            new CssClass('block__element'),
            new CssClass('block--modifier'),
            new CssClass('block__element--modifier'),
        ];

        $bemValidation = $this->checker->validateFrameworkConventions($bemClasses, 'bem');
        expect($bemValidation['compliant'])->toHaveCount(4);
    });
});
