<?php

declare(strict_types=1);

final class MyronSectionRendererRegistry
{
    /** @var array<string, array{renderer:MyronSectionRenderer,order:int}> */
    private array $entries = [];
    private int $registrationOrder = 0;

    public function register(MyronSectionRenderer $renderer): void
    {
        $id = trim($renderer->id());
        if ($id === '') {
            throw new InvalidArgumentException('Section renderer id is required.');
        }
        if (isset($this->entries[$id])) {
            throw new LogicException('Duplicate section renderer id: ' . $id);
        }
        $this->entries[$id] = [
            'renderer' => $renderer,
            'order' => $this->registrationOrder++,
        ];
    }

    public function resolve(MyronSectionRenderContext $context): ?MyronSectionRenderer
    {
        $entries = array_values($this->entries);
        usort($entries, static function (array $left, array $right): int {
            $priority = $right['renderer']->priority() <=> $left['renderer']->priority();
            return $priority !== 0 ? $priority : ($left['order'] <=> $right['order']);
        });
        foreach ($entries as $entry) {
            if ($entry['renderer']->canRender($context)) {
                return $entry['renderer'];
            }
        }
        return null;
    }

    public function render(MyronSectionRenderContext $context): string
    {
        $renderer = $this->resolve($context);
        if (!$renderer instanceof MyronSectionRenderer) {
            throw new LogicException('No section renderer accepted component: ' . $context->componentId);
        }
        return $renderer->render($context);
    }

    public function contractForComponent(string $componentId, array $section = [], array $content = []): ?MyronSectionContract
    {
        $componentId = trim($componentId);
        if ($componentId === '') {
            return null;
        }
        $section['componentId'] = $componentId;
        $context = new MyronSectionRenderContext(
            $componentId,
            trim((string) ($section['variant'] ?? '')),
            trim((string) ($section['notes'] ?? '')),
            myronNormalizeSlug((string) (($section['notes'] ?? '') ?: ($section['variant'] ?? '') ?: $componentId)),
            0,
            $section,
            $content,
            '/',
            trim((string) ($section['sourceBundleId'] ?? '')),
            trim((string) ($section['sourceTemplateId'] ?? '')),
            false,
            false,
            false,
            trim((string) ($content['headline'] ?? '')),
            trim((string) (($content['body'] ?? '') ?: ($content['intro'] ?? ''))),
            'myron-definition-section myron-definition-section--' . myronNormalizeSlug($componentId),
        );
        return $this->resolve($context)?->contract();
    }

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