<?php

declare(strict_types=1);

final class MyronCurrentSiteUsageReadModel
{
    public function __construct(
        private readonly MyronContentRepository $content,
        private readonly MyronSectionRegistryRepository $sections,
        private readonly MyronLiveSectionInventoryReadModel $liveSections,
    ) {
    }

    /**
     * @return array<string, array{sourceTemplateId:string,runtimeTemplateId:string,templateKey:string,name:string,pageCount:int,pages:list<array<string, mixed>>}>
     */
    public function templateUsageIndex(): array
    {
        $templatesById = $this->runtimeTemplatesById();
        $index = [];

        foreach ($this->content->listPages() as $page) {
            $runtimeTemplateId = trim((string) ($page['template_id'] ?? ''));
            $runtimeTemplate = $templatesById[$runtimeTemplateId] ?? null;
            $sourceTemplateId = $this->sourceTemplateIdForPage($page, $runtimeTemplate);
            if ($sourceTemplateId === '') {
                continue;
            }

            if (!isset($index[$sourceTemplateId])) {
                $index[$sourceTemplateId] = [
                    'sourceTemplateId' => $sourceTemplateId,
                    'runtimeTemplateId' => $runtimeTemplateId,
                    'templateKey' => is_array($runtimeTemplate) ? (string) ($runtimeTemplate['template_key'] ?? '') : (string) ($page['template_key'] ?? ''),
                    'name' => is_array($runtimeTemplate) ? (string) ($runtimeTemplate['name'] ?? '') : (string) ($page['template_name'] ?? ''),
                    'pageCount' => 0,
                    'pages' => [],
                ];
            }

            $index[$sourceTemplateId]['pageCount']++;
            $index[$sourceTemplateId]['pages'][] = [
                'id' => (string) ($page['id'] ?? ''),
                'title' => (string) ($page['title'] ?? ''),
                'path' => (string) ($page['path'] ?? ''),
                'runtimeTemplateId' => $runtimeTemplateId,
                'publicationState' => (string) ($page['publication_state'] ?? ''),
            ];
        }

        ksort($index);
        return $index;
    }

    /**
     * @return list<string>
     */
    public function currentTemplateSourceIds(): array
    {
        return array_keys($this->templateUsageIndex());
    }

    /**
     * @return array<string, list<array{pageId:string,pagePath:string,pageTitle:string,sourceTemplateId:string,runtimeTemplateId:string,position:int,matchedBy:string}>>
     */
    public function sectionUsageIndex(): array
    {
        $index = [];

        foreach ($this->liveSections->inventoryIndex() as $identityKey => $section) {
            $index[$identityKey] = is_array($section['usages'] ?? null) ? $section['usages'] : [];
        }

        ksort($index);
        return $index;
    }

    /**
     * @return list<string>
     */
    public function currentSectionKeys(): array
    {
        return array_keys($this->sectionUsageIndex());
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    public function liveSectionInventoryIndex(): array
    {
        return $this->liveSections->inventoryIndex();
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function liveSectionInventoryRows(): array
    {
        return $this->liveSections->inventoryRows();
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    public function governedSectionInventoryIndex(): array
    {
        $sectionsByKey = [];
        foreach ($this->sections->listSections() as $section) {
            $sectionKey = trim((string) ($section['sectionKey'] ?? ''));
            if ($sectionKey !== '') {
                $section['usageCount'] = 0;
                $section['usages'] = [];
                $section['sourceTemplateIds'] = [];
                $section['runtimeTemplateIds'] = [];
                $section['renderComponents'] = [];
                $section['componentId'] = (string) ((is_array($section['primaryComponents'] ?? null) ? ($section['primaryComponents'][0] ?? '') : '') ?: $sectionKey);
                $section['variant'] = '';
                $sectionsByKey[$sectionKey] = $section;
            }
        }

        foreach ($this->liveSections->inventoryRows() as $liveRow) {
            foreach (is_array($liveRow['usages'] ?? null) ? $liveRow['usages'] : [] as $usage) {
                if (!is_array($usage)) {
                    continue;
                }

                $sectionKey = trim((string) ($usage['sectionKey'] ?? $liveRow['sectionKey'] ?? ''));
                if ($sectionKey === '' || !isset($sectionsByKey[$sectionKey])) {
                    continue;
                }

                $componentId = trim((string) ($usage['componentId'] ?? $liveRow['componentId'] ?? ''));
                $variant = trim((string) ($usage['variant'] ?? $liveRow['variant'] ?? ''));
                $componentLabel = $componentId . ($variant !== '' ? ' / ' . $variant : '');
                if ($componentLabel !== '') {
                    $sectionsByKey[$sectionKey]['renderComponents'][$componentLabel] = $componentLabel;
                }
                if (($sectionsByKey[$sectionKey]['usageCount'] ?? 0) === 0 && $componentId !== '') {
                    $sectionsByKey[$sectionKey]['componentId'] = $componentId;
                    $sectionsByKey[$sectionKey]['variant'] = $variant;
                    $sectionsByKey[$sectionKey]['defaultContent'] = is_array($liveRow['defaultContent'] ?? null) ? $liveRow['defaultContent'] : [];
                    $sectionsByKey[$sectionKey]['defaultContentEditable'] = $liveRow['defaultContentEditable'] ?? ($sectionsByKey[$sectionKey]['defaultContentEditable'] ?? null);
                    $sectionsByKey[$sectionKey]['defaultContentSource'] = (string) ($liveRow['defaultContentSource'] ?? 'registry');
                    $sectionsByKey[$sectionKey]['flags'] = is_array($liveRow['flags'] ?? null) ? $liveRow['flags'] : [];
                }

                $sectionsByKey[$sectionKey]['usageCount']++;
                $sectionsByKey[$sectionKey]['usages'][] = $usage;

                $sourceTemplateId = trim((string) ($usage['sourceTemplateId'] ?? ''));
                if ($sourceTemplateId !== '') {
                    $sectionsByKey[$sectionKey]['sourceTemplateIds'][$sourceTemplateId] = $sourceTemplateId;
                }

                $runtimeTemplateId = trim((string) ($usage['runtimeTemplateId'] ?? ''));
                if ($runtimeTemplateId !== '') {
                    $sectionsByKey[$sectionKey]['runtimeTemplateIds'][$runtimeTemplateId] = $runtimeTemplateId;
                }
            }
        }

        $sectionsByKey = array_filter(
            $sectionsByKey,
            static fn (array $section): bool => (int) ($section['usageCount'] ?? 0) > 0
        );

        foreach ($sectionsByKey as &$section) {
            $section['renderComponents'] = array_values(is_array($section['renderComponents'] ?? null) ? $section['renderComponents'] : []);
            $section['primaryComponents'] = $section['renderComponents'] !== []
                ? $section['renderComponents']
                : (is_array($section['primaryComponents'] ?? null) ? $section['primaryComponents'] : []);
            $section['sourceTemplateIds'] = array_values(is_array($section['sourceTemplateIds'] ?? null) ? $section['sourceTemplateIds'] : []);
            $section['runtimeTemplateIds'] = array_values(is_array($section['runtimeTemplateIds'] ?? null) ? $section['runtimeTemplateIds'] : []);
            $section['identityKey'] = (string) ($section['sectionKey'] ?? '');
        }
        unset($section);

        uasort(
            $sectionsByKey,
            static fn (array $a, array $b): int => [(string) ($a['label'] ?? ''), (string) ($a['sectionKey'] ?? '')] <=> [(string) ($b['label'] ?? ''), (string) ($b['sectionKey'] ?? '')]
        );

        return $sectionsByKey;
    }

    /**
     * @return list<array<string, mixed>>
     */
    public function governedSectionInventoryRows(): array
    {
        return array_values($this->governedSectionInventoryIndex());
    }

    /**
     * @return array<string, mixed>|null
     */
    public function findGovernedSectionByKey(string $sectionKey): ?array
    {
        return $this->governedSectionInventoryIndex()[trim($sectionKey)] ?? null;
    }

    /**
     * @return array<string, array<string, mixed>>
     */
    private function runtimeTemplatesById(): array
    {
        $templates = [];
        foreach ($this->content->listTemplates() as $template) {
            $templateId = trim((string) ($template['id'] ?? ''));
            if ($templateId !== '') {
                $templates[$templateId] = $template;
            }
        }

        return $templates;
    }

    /**
     * @param array<string, mixed>|null $runtimeTemplate
     */
    private function sourceTemplateIdForPage(array $page, ?array $runtimeTemplate): string
    {
        $pageSourceTemplateId = trim((string) ($page['source_template_id'] ?? ''));
        if ($pageSourceTemplateId !== '') {
            return $pageSourceTemplateId;
        }

        return is_array($runtimeTemplate) ? trim((string) ($runtimeTemplate['source_template_id'] ?? '')) : '';
    }

}
