<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Twig;

use Gls\GlsPoland\DependencyInjection\ServiceSubscriberInterface;
use Gls\GlsPoland\PrestaShop\Hook\RecursionHandlingHookDispatcher;
use PrestaShop\PrestaShop\Core\Hook\HookDispatcher;
use PrestaShop\PrestaShop\Core\Hook\HookDispatcherInterface;
use Psr\Container\ContainerInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

/**
 * @internal
 *
 * Simply decorating the "prestashop.hook.dispatcher" service in the DI container would have been a more sane approach,
 * but service decoration may cause problems on PS 8.x if the container cache is not cleared after the module is disabled
 * (and cache is not cleared by default on 8.x).
 */
final class HookExtension extends AbstractExtension implements ServiceSubscriberInterface
{
    /**
     * @var ContainerInterface
     */
    private $container;

    /**
     * @var HookDispatcherInterface
     */
    private $dispatcher;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public static function getSubscribedServices(): array
    {
        return [
            'prestashop.hook.dispatcher' => HookDispatcherInterface::class,
        ];
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('renderhook', [$this, 'renderHook'], ['is_safe' => ['html']]),
        ];
    }

    public function renderHook(string $hookName, array $hookParameters = []): string
    {
        if ('' === $hookName) {
            throw new \Exception('Hook name missing');
        }

        return $this
            ->getDispatcher()
            ->dispatchRenderingWithParameters($hookName, $hookParameters)
            ->outputContent();
    }

    private function getDispatcher(): HookDispatcherInterface
    {
        return $this->dispatcher ?? $this->dispatcher = $this->createDispatcher();
    }

    private function createDispatcher(): HookDispatcherInterface
    {
        $dispatcher = $this->container->get('prestashop.hook.dispatcher');
        $dispatcher = new RecursionHandlingHookDispatcher($dispatcher);

        return new HookDispatcher($dispatcher);
    }
}
