<?php

declare(strict_types=1);

final class MyronComponentPreviewCatalog
{
    /**
     * @var array<string, array{title: string, description: string, ids: list<string>}>
     */
    private const GROUPS = [
        'text-media' => [
            'title' => 'Text and Media',
            'description' => 'Typography, inline content, media, and readable content primitives.',
            'ids' => [
                'text', 'paragraph', 'heading', 'link', 'inline-code', 'code-block', 'list', 'list-item',
                'quote', 'table', 'card', 'image', 'figure', 'icon', 'logo', 'video', 'cms-content-title',
                'cms-content-body', 'cms-content-excerpt', 'cms-featured-media', 'cms-embed',
            ],
        ],
        'layout-structure' => [
            'title' => 'Layout and Structure',
            'description' => 'Containers, spatial systems, structural grids, and page bands.',
            'ids' => [
                'container', 'stack', 'grid', 'columns', 'spacer', 'separator', 'section-band',
                'cms-collection-query', 'cms-collection-template', 'cms-pagination',
            ],
        ],
        'controls-forms' => [
            'title' => 'Controls and Forms',
            'description' => 'Inputs, form composition, selectors, and interaction controls.',
            'ids' => [
                'button', 'input', 'textarea', 'select', 'checkbox', 'radio', 'switch', 'combobox',
                'datepicker', 'timepicker', 'datetime-picker', 'form-field', 'form-hint', 'help-text',
                'error-text', 'auth-form', 'sign-in-form', 'contact-form-with-info', 'newsletter-signup',
            ],
        ],
        'navigation-overlays' => [
            'title' => 'Navigation and Overlays',
            'description' => 'Site navigation, menus, tabs, pagination, and temporary surfaces.',
            'ids' => [
                'header', 'footer', 'breadcrumbs', 'tabs', 'tab-list', 'tab', 'tab-panel', 'pagination',
                'sidebar-nav', 'sub-nav-bar', 'menu-block', 'dropdown-menu', 'drawer', 'dialog', 'popover',
                'tooltip', 'carousel',
            ],
        ],
        'status-feedback' => [
            'title' => 'Status and Feedback',
            'description' => 'System feedback, loading states, badges, and proof points.',
            'ids' => [
                'alert', 'toast', 'badge', 'chip', 'progress-bar', 'skeleton', 'empty-state', 'stats-tile',
                'banner',
            ],
        ],
        'public-sections' => [
            'title' => 'Public Sections',
            'description' => 'Marketing, editorial, portfolio, education, and site-content sections.',
            'ids' => [
                'hero-simple', 'hero-with-cta', 'feature-grid', 'services-grid', 'testimonial-grid',
                'portfolio-grid', 'blog-teaser', 'team-grid', 'course-catalog', 'resources-item-card',
                'featured-offer-card', 'legal-doc-toc', 'faq-list', 'cta-band', 'pricing-table', 'tier-comparison-matrix',
            ],
        ],
        'administration-files' => [
            'title' => 'Administration and Files',
            'description' => 'User management, file management, page metadata, and workspace panels.',
            'ids' => [
                'avatar', 'user-handle', 'user-identity', 'user-row', 'user-list', 'role-badge',
                'permission-matrix-row', 'profile-summary-card', 'profile-panel', 'settings-layout',
                'access-management-panel', 'invite-user-form', 'avatar-upload-panel', 'kv-row',
                'copy-field', 'dropzone', 'upload-queue-item', 'upload-panel', 'file-row', 'file-list',
                'file-meta-panel', 'bulk-actions-bar', 'table-toolbar', 'share-panel',
                'page-attributes-panel', 'featured-media-picker', 'seo-fields-panel', 'data-table',
                'revision-activity-list', 'activity-item',
            ],
        ],
        'commerce-conversion' => [
            'title' => 'Commerce and Conversion',
            'description' => 'Product, cart, checkout, booking, and conversion-oriented components.',
            'ids' => [
                'price-display', 'quantity-stepper', 'rating-summary', 'product-card', 'variant-selector',
                'product-gallery', 'cart-line-item', 'order-summary', 'cart-drawer', 'cart-table',
                'product-filters', 'product-sort-control', 'product-grid', 'product-details',
                'related-products', 'checkout-stepper', 'checkout-address-form', 'shipping-method-selector',
                'payment-method-selector', 'payment-form', 'checkout-review', 'checkout-confirmation',
                'registration-form', 'password-recovery-request-form', 'password-reset-form',
                'lead-magnet-card',
            ],
        ],
    ];

    /**
     * @var array<string, string>
     */
    private const ENVELOPES = [
        'activity-item' => 'panel',
        'alert' => 'narrow',
        'avatar' => 'intrinsic',
        'badge' => 'intrinsic',
        'button' => 'intrinsic',
        'checkbox' => 'intrinsic',
        'chip' => 'intrinsic',
        'copy-field' => 'control',
        'cta-band' => 'full-bleed',
        'dropdown-menu' => 'narrow',
        'form-field' => 'control',
        'header' => 'full-bleed',
        'hero-simple' => 'full-bleed',
        'hero-with-cta' => 'full-bleed',
        'icon' => 'intrinsic',
        'input' => 'control',
        'link' => 'intrinsic',
        'logo' => 'contained-section',
        'newsletter-signup' => 'narrow',
        'pagination' => 'intrinsic',
        'paragraph' => 'narrow',
        'progress-bar' => 'narrow',
        'radio' => 'intrinsic',
        'select' => 'control',
        'separator' => 'full-bleed',
        'spacer' => 'full-bleed',
        'switch' => 'intrinsic',
        'table-toolbar' => 'toolbar',
        'tabs' => 'panel',
        'textarea' => 'control',
        'text' => 'intrinsic',
        'toast' => 'narrow',
        'tooltip' => 'intrinsic',
        'upload-queue-item' => 'panel',
        'user-handle' => 'intrinsic',
    ];

    /**
     * @return list<array{key: string, title: string, description: string, components: list<array<string, mixed>>}>
     */
    public function groupComponents(array $components): array
    {
        $groups = [];
        $seen = [];

        foreach (self::GROUPS as $key => $group) {
            $groups[$key] = [
                'key' => $key,
                'title' => $group['title'],
                'description' => $group['description'],
                'components' => [],
            ];
        }
        $groups['other'] = [
            'key' => 'other',
            'title' => 'Other Components',
            'description' => 'Registered components that do not yet map to a named display family.',
            'components' => [],
        ];

        foreach ($components as $component) {
            if (!is_array($component)) {
                continue;
            }

            $componentId = $this->componentId($component);
            if ($componentId === '' || isset($seen[$componentId])) {
                continue;
            }

            $groupKey = $this->groupKey($component);
            $groups[$groupKey]['components'][] = $component;
            $seen[$componentId] = true;
        }

        foreach ($groups as $key => $group) {
            usort(
                $groups[$key]['components'],
                fn (array $left, array $right): int => $this->componentId($left) <=> $this->componentId($right)
            );
        }

        return array_values(array_filter(
            $groups,
            static fn (array $group): bool => $group['components'] !== []
        ));
    }

    /**
     * @param array<string, mixed> $component
     */
    public function matchesSearch(array $component, string $query): bool
    {
        $normalized = strtolower(trim($query));
        if ($normalized === '') {
            return true;
        }

        $haystack = implode(' ', [
            $this->componentId($component),
            (string) ($component['purpose'] ?? ''),
            $this->groupTitle($component),
            (string) ($component['implementationNotes'] ?? ''),
        ]);

        return str_contains(strtolower($haystack), $normalized);
    }

    /**
     * @param array<string, mixed> $component
     */
    public function previewEnvelope(array $component): string
    {
        $componentId = $this->componentId($component);
        if (isset(self::ENVELOPES[$componentId])) {
            return self::ENVELOPES[$componentId];
        }

        $composedOf = is_array($component['composedOf'] ?? null) ? array_map('strval', $component['composedOf']) : [];
        $slots = is_array($component['slots'] ?? null) ? array_keys($component['slots']) : [];

        if (str_contains($componentId, 'grid') || str_contains($componentId, 'catalog')) {
            return 'grid';
        }
        if (str_contains($componentId, 'toolbar') || str_contains($componentId, 'actions-bar')) {
            return 'toolbar';
        }
        if (str_contains($componentId, 'panel') || str_contains($componentId, 'drawer') || str_contains($componentId, 'table')) {
            return 'panel';
        }
        if (str_contains($componentId, 'form') || str_contains($componentId, 'picker') || in_array('input', $composedOf, true) || in_array('select', $composedOf, true)) {
            return 'narrow';
        }
        if (str_contains($componentId, 'band') || str_contains($componentId, 'hero') || $componentId === 'footer') {
            return 'full-bleed';
        }
        if (count($slots) <= 1 && $composedOf === []) {
            return 'intrinsic';
        }

        return 'contained-section';
    }

    /**
     * @param array<string, mixed> $component
     */
    public function specimenLabel(array $component): string
    {
        return match ($this->previewEnvelope($component)) {
            'intrinsic' => 'intrinsic live preview',
            'control' => 'control-width live preview',
            'narrow' => 'narrow live preview',
            'panel' => 'panel live preview',
            'toolbar' => 'toolbar live preview',
            'grid' => 'grid live preview',
            'full-bleed' => 'full-bleed live preview',
            default => 'contained live preview',
        };
    }

    /**
     * @param array<string, mixed> $component
     */
    private function groupKey(array $component): string
    {
        $componentId = $this->componentId($component);
        foreach (self::GROUPS as $key => $group) {
            if (in_array($componentId, $group['ids'], true)) {
                return $key;
            }
        }

        return 'other';
    }

    /**
     * @param array<string, mixed> $component
     */
    private function groupTitle(array $component): string
    {
        $key = $this->groupKey($component);
        return self::GROUPS[$key]['title'] ?? 'Other Components';
    }

    /**
     * @param array<string, mixed> $component
     */
    private function componentId(array $component): string
    {
        return myronNormalizeSlug((string) ($component['id'] ?? ''));
    }
}
