<?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\TaskBundle\Timeline;

use Chill\MainBundle\Timeline\TimelineProviderInterface;
use Chill\MainBundle\Timeline\TimelineSingleQuery;
use Chill\TaskBundle\Entity\SingleTask;
use Chill\TaskBundle\Entity\Task\SingleTaskPlaceEvent;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Workflow;

/**
 * Provide timeline elements related to tasks, in tasks context.
 */
class SingleTaskTaskLifeCycleEventTimelineProvider implements TimelineProviderInterface
{
    final public const TYPE = 'chill_task.transition';

    /**
     * @var EntityManagerInterface
     */
    protected $em;

    /**
     * @var Registry
     */
    protected $registry;

    public function __construct(EntityManagerInterface $em, Registry $registry)
    {
        $this->em = $em;
        $this->registry = $registry;
    }

    public function fetchQuery($context, $args)
    {
        if ('task' !== $context) {
            throw new \LogicException(sprintf('%s is not able to render context %s', self::class, $context));
        }

        $metadata = $this->em
            ->getClassMetadata(SingleTaskPlaceEvent::class);
        $singleTaskMetadata = $this->em
            ->getClassMetadata(SingleTask::class);

        return TimelineSingleQuery::fromArray([
            'id' => sprintf('%s.%s.%s', $metadata->getSchemaName(), $metadata->getTableName(), $metadata->getColumnName('id')),
            'type' => self::TYPE,
            'date' => $metadata->getColumnName('datetime'),
            'FROM' => sprintf(
                '%s JOIN %s ON %s = %s',
                sprintf('%s.%s', $metadata->getSchemaName(), $metadata->getTableName()),
                sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
                $metadata->getAssociationMapping('task')['joinColumns'][0]['name'],
                sprintf('%s.%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName(), $singleTaskMetadata->getColumnName('id'))
            ),
            'WHERE' => sprintf(
                '%s.%s = %d',
                sprintf('%s.%s', $singleTaskMetadata->getSchemaName(), $singleTaskMetadata->getTableName()),
                $singleTaskMetadata->getColumnName('id'),
                $args['task']->getId()
            ),
            'parameters' => [],
        ]);
    }

    public function getEntities(array $ids)
    {
        $events = $this->em
            ->getRepository(SingleTaskPlaceEvent::class)
            ->findBy(['id' => $ids]);

        return \array_combine(
            \array_map(static fn ($e) => $e->getId(), $events),
            $events
        );
    }

    public function getEntityTemplate($entity, $context, array $args)
    {
        if (isset($entity->getData()['workflow'])) {
            $workflow = $this->registry->get($entity->getTask(), $entity->getData()['workflow']);
            $transition = $this->getTransitionByName($entity->getTransition(), $workflow);
        }

        return [
            'template' => '@ChillTask/Timeline/single_task_transition_task_context.html.twig',
            'template_data' => [
                'task' => $args['task'],
                'event' => $entity,
                'transition' => $transition ?? null,
            ],
        ];
    }

    public function supportsType($type): bool
    {
        return self::TYPE === $type;
    }

    /**
     * @param string $name
     *
     * @return \Symfony\Component\Workflow\Transition
     */
    protected function getTransitionByName($name, Workflow $workflow)
    {
        foreach ($workflow->getDefinition()->getTransitions() as $transition) {
            if ($transition->getName() === $name) {
                return $transition;
            }
        }
    }
}
