<?php
declare(strict_types=1);

namespace Celena\Core\Template;

/**
 * Реестр тегов и блоков шаблонизатора.
 *
 * Inline-теги: {имя param="x"}
 *   handler: callable (array $params, array $vars): string  — или TagInterface
 *
 * Block-теги: [имя param="x"] body [/имя]
 *   handler: callable (array $params, array $vars, callable $renderBody): string
 *   $renderBody — function (array $vars): string, рендерит тело блока
 *   с произвольным набором переменных (для итераций).
 */
final class TagRegistry
{
    /** @var array<string, callable|TagInterface|string> */
    private array $inline = [];

    /** @var array<string, callable|string> */
    private array $blocks = [];

    public function registerInline(string $name, callable|TagInterface|string $handler): void
    {
        $this->inline[strtolower($name)] = $handler;
    }

    public function registerBlock(string $name, callable|string $handler): void
    {
        $this->blocks[strtolower($name)] = $handler;
    }

    public function hasInline(string $name): bool { return isset($this->inline[strtolower($name)]); }
    public function hasBlock(string $name): bool  { return isset($this->blocks[strtolower($name)]); }

    public function renderInline(string $name, array $params, array $vars): string
    {
        $h = $this->inline[strtolower($name)] ?? null;
        if ($h === null) {
            return '';
        }
        if (is_string($h) && class_exists($h)) {
            $h = new $h();
        }
        if ($h instanceof TagInterface) {
            return $h->render($params, $vars, null);
        }
        if (is_callable($h)) {
            return (string) $h($params, $vars);
        }
        return '';
    }

    public function resolveBlockHandler(string $name): callable|string|null
    {
        return $this->blocks[strtolower($name)] ?? null;
    }

    /** @return string[] */
    public function inlineNames(): array { return array_keys($this->inline); }

    /** @return string[] */
    public function blockNames(): array { return array_keys($this->blocks); }
}
