<?php

namespace App\Service\SnipParser\Generic;

use App\Repository\SnipRepository;
use App\Security\Voter\SnipVoter;
use League\Pipeline\StageInterface;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

readonly class UrlReferenceStage implements StageInterface
{
    public function __construct(
        #[Autowire(lazy: true)] private UrlGeneratorInterface $router,
        #[Autowire(lazy: true)] private Security              $security,
        #[Autowire(lazy: true)] private SnipRepository        $snipRepository,
    ) {}

    public function __invoke(mixed $payload): string
    {
        return $this->replaceReferences($payload);
    }

    private function replaceReferences(mixed $payload): string
    {
        // replaces all references (#n) to other snips with links
        $pattern = '/#(\d+)/';

        return preg_replace_callback($pattern, function ($matches) {
            $snip = $this->snipRepository->find($matches[1]);
            if ($snip === null) {
                return sprintf('<span title="not found">%s</span>', $matches[0]);
            }
            if (!$this->security->isGranted(SnipVoter::VIEW, $snip)) {
                return sprintf('<span title="access denied">%s</span>', $matches[0]);
            }

            $url = $this->router->generate('snip_single', ['snip' => $snip->id]);
            return sprintf('<a href="%s">%s</a>', $url, $snip);
        }, $payload);
    }
}
