<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\Workflow\Templating;

use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Workflow\Helper\MetadataExtractor;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Transition;
use Twig\Environment;
use Twig\Extension\RuntimeExtensionInterface;

class WorkflowTwigExtensionRuntime implements RuntimeExtensionInterface
{
    public function __construct(private readonly Registry $registry, private readonly EntityWorkflowRepository $repository, private readonly MetadataExtractor $metadataExtractor, private readonly NormalizerInterface $normalizer) {}

    public function getTransitionByString(EntityWorkflow $entityWorkflow, string $key): ?Transition
    {
        $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
        $transitions = $workflow->getDefinition()->getTransitions();

        foreach ($transitions as $transition) {
            if ($transition->getName() === $key) {
                return $transition;
            }
        }

        return null;
    }

    /**
     * @param array<array{relatedEntityClass: string, relatedEntityId: int}> $supplementaryRelated
     *
     * @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     */
    public function listWorkflows(Environment $environment, string $relatedEntityClass, int $relatedEntityId, array $options = [], array $supplementaryRelated = []): string
    {
        [$blankEntityWorkflow, $workflowsAvailable, $entityWorkflows] = $this->getWorkflowsForRelated($relatedEntityClass, $relatedEntityId);

        foreach ($supplementaryRelated as $supplementary) {
            [$supplementaryBlankEntityWorkflow, $supplementaryWorkflowsAvailable, $supplementaryEntityWorkflows]
                = $this->getWorkflowsForRelated($supplementary['relatedEntityClass'], $supplementary['relatedEntityId']);

            $entityWorkflows = array_merge($entityWorkflows, $supplementaryEntityWorkflows);
        }

        return $environment->render('@ChillMain/Workflow/_extension_list_workflow_for.html.twig', [
            'entity_workflows_json' => $this->normalizer->normalize($entityWorkflows, 'json', ['groups' => 'read']),
            'workflows_available' => $workflowsAvailable,
            'relatedEntityClass' => $relatedEntityClass,
            'relatedEntityId' => $relatedEntityId,
        ]);
    }

    /**
     * @return array where keys are: {0: blankWorkflow, 1: entityWorkflows, 2: workflowList}
     */
    private function getWorkflowsForRelated(string $relatedEntityClass, int $relatedEntityId): array
    {
        $blankEntityWorkflow = new EntityWorkflow();
        $blankEntityWorkflow
            ->setRelatedEntityId($relatedEntityId)
            ->setRelatedEntityClass($relatedEntityClass);

        $workflowsList = $this->metadataExtractor->availableWorkflowFor($relatedEntityClass, $relatedEntityId);

        return
            [
                $blankEntityWorkflow,
                $workflowsList,
                $this->repository->findBy(
                    ['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId]
                ),
            ];
    }
}
