<?php

declare(strict_types=1);

/**
 * MyronPrimitiveExplorerService — data layer for the Primitive Explorer side-sheet.
 *
 * Given a primitive id, returns the archetype-realized usages from the live
 * `template_definitions` table grouped by `(bundleId, templateId)`. Each group
 * carries enough information for the UI to render a representative specimen via
 * `MyronPrimitiveRenderer::renderById($primitiveId, $props, $archetypeContext)`.
 *
 * This is the surface that satisfies the operator's "composed primitives must
 * reflect actual usage in page templates" requirement WITHOUT introducing a
 * components classification — archetype context lives on the template, the
 * renderer specializes at render time, and this service simply enumerates
 * the (primitive × archetype) pairs that exist in the catalog.
 */
final class MyronPrimitiveExplorerService
{
    public function __construct(
        private readonly MyronTemplateDefinitionRepository $templateRepository,
        private readonly MyronComponentRegistryRepository $componentRepository,
    ) {
    }

    /**
     * @return array<string, mixed> {
     *   primitiveId: string,
     *   classification: string,
     *   registryAddress: string,
     *   tokenDependencies: list<string>,
     *   variants: list<array<string, mixed>>,
     *   usages: list<array{ bundleId: string, templateId: string, sectionVariant: string, sectionNotes: string, templateName: string, sectionIndex: int }>,
     *   usageCount: int,
     *   bundleCount: int,
     * }
     */
    public function describe(string $primitiveId): array
    {
        $id = trim($primitiveId);
        if ($id === '') {
            return [
                'primitiveId' => '',
                'classification' => '',
                'registryAddress' => '',
                'tokenDependencies' => [],
                'variants' => [],
                'usages' => [],
                'usageCount' => 0,
                'bundleCount' => 0,
            ];
        }

        $component = $this->componentRepository->findComponentById($id);
        $registry = is_array($component['_registry'] ?? null) ? $component['_registry'] : [];
        $variants = is_array($component['variants'] ?? null) ? $component['variants'] : [];
        $tokenDeps = is_array($component['tokenDependencies'] ?? null)
            ? array_values(array_map('strval', $component['tokenDependencies']))
            : [];

        $usages = $this->collectUsages($id);
        $bundleIds = [];
        foreach ($usages as $u) {
            $bundleIds[$u['bundleId']] = true;
        }

        return [
            'primitiveId' => $id,
            'classification' => (string) ($registry['classification'] ?? ($component['classification'] ?? '')),
            'registryAddress' => (string) ($registry['registryAddress'] ?? ($component['registryAddress'] ?? '')),
            'tokenDependencies' => $tokenDeps,
            'variants' => array_values(array_filter($variants, 'is_array')),
            'usages' => $usages,
            'usageCount' => count($usages),
            'bundleCount' => count($bundleIds),
        ];
    }

    /**
     * @return list<array{ bundleId: string, templateId: string, sectionVariant: string, sectionNotes: string, templateName: string, sectionIndex: int }>
     */
    private function collectUsages(string $primitiveId): array
    {
        $rows = $this->templateRepository->listTemplates();
        $usages = [];
        foreach ($rows as $row) {
            $sections = is_array($row['sections'] ?? null) ? $row['sections'] : [];
            foreach ($sections as $i => $section) {
                if (!is_array($section)) {
                    continue;
                }
                if ((string) ($section['componentId'] ?? '') !== $primitiveId) {
                    continue;
                }
                $registry = is_array($row['_registry'] ?? null) ? $row['_registry'] : [];
                $usages[] = [
                    'bundleId' => (string) ($registry['bundleId'] ?? $row['bundleId'] ?? ''),
                    'templateId' => (string) ($row['id'] ?? ''),
                    'templateName' => (string) ($row['name'] ?? ''),
                    'sectionVariant' => (string) ($section['variant'] ?? ''),
                    'sectionNotes' => (string) ($section['notes'] ?? ''),
                    'sectionIndex' => (int) $i,
                ];
            }
        }

        usort(
            $usages,
            static fn (array $a, array $b): int => [$a['bundleId'], $a['templateId'], $a['sectionIndex']] <=> [$b['bundleId'], $b['templateId'], $b['sectionIndex']]
        );

        return $usages;
    }

    /**
     * Group usages into archetype clusters (bundleId, templateId) for UI rendering.
     *
     * @param list<array<string, mixed>> $usages
     * @return list<array{ bundleId: string, templateId: string, templateName: string, occurrences: list<array<string, mixed>> }>
     */
    public function groupByArchetype(array $usages): array
    {
        $groups = [];
        foreach ($usages as $u) {
            $key = ($u['bundleId'] ?? '') . '|' . ($u['templateId'] ?? '');
            if (!isset($groups[$key])) {
                $groups[$key] = [
                    'bundleId' => (string) ($u['bundleId'] ?? ''),
                    'templateId' => (string) ($u['templateId'] ?? ''),
                    'templateName' => (string) ($u['templateName'] ?? ''),
                    'occurrences' => [],
                ];
            }
            $groups[$key]['occurrences'][] = $u;
        }

        return array_values($groups);
    }
}
