<?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\Form;

use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Form\Type\ChillCollectionType;
use Chill\MainBundle\Form\Type\ChillTextareaType;
use Chill\MainBundle\Form\Type\PickUserDynamicType;
use Chill\MainBundle\Form\Type\PickUserGroupOrUserDynamicType;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
use Chill\PersonBundle\Form\Type\PickPersonDynamicType;
use Chill\ThirdPartyBundle\Form\Type\PickThirdpartyDynamicType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\Workflow\Transition;

class WorkflowStepType extends AbstractType
{
    public function __construct(
        private readonly Registry $registry,
        private readonly TranslatableStringHelperInterface $translatableStringHelper,
        private readonly EntityWorkflowManager $entityWorkflowManager,
    ) {}

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        /** @var EntityWorkflow $entityWorkflow */
        $entityWorkflow = $options['entity_workflow'];
        $workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
        $place = $workflow->getMarking($entityWorkflow);
        $placeMetadata = $workflow->getMetadataStore()->getPlaceMetadata(array_keys($place->getPlaces())[0]);
        $suggestedUsers = $this->entityWorkflowManager->getSuggestedUsers($entityWorkflow);
        $suggestedThirdParties = $this->entityWorkflowManager->getSuggestedThirdParties($entityWorkflow);
        $suggestedPersons = $this->entityWorkflowManager->getSuggestedPersons($entityWorkflow);

        if (null === $options['entity_workflow']) {
            throw new \LogicException('if transition is true, entity_workflow should be defined');
        }

        $transitions = $this->registry
            ->get($options['entity_workflow'], $entityWorkflow->getWorkflowName())
            ->getEnabledTransitions($entityWorkflow);

        $choices = array_combine(
            array_map(
                static fn (Transition $transition) => $transition->getName(),
                $transitions
            ),
            $transitions
        );

        if (\array_key_exists('validationFilterInputLabels', $placeMetadata)) {
            $inputLabels = $placeMetadata['validationFilterInputLabels'];

            $builder->add('transitionFilter', ChoiceType::class, [
                'multiple' => false,
                'label' => 'workflow.My decision',
                'choices' => [
                    'forward' => 'forward',
                    'backward' => 'backward',
                    'neutral' => 'neutral',
                ],
                'choice_label' => fn (string $key) => $this->translatableStringHelper->localize($inputLabels[$key]),
                'choice_attr' => static fn (string $key) => [
                    $key => $key,
                ],
                'mapped' => false,
                'expanded' => true,
                'data' => 'forward',
            ]);
        }

        $builder
            ->add('transition', ChoiceType::class, [
                'label' => 'workflow.Next step',
                'multiple' => false,
                'expanded' => true,
                'choices' => $choices,
                'constraints' => [new NotNull()],
                'choice_label' => function (Transition $transition) use ($workflow) {
                    $meta = $workflow->getMetadataStore()->getTransitionMetadata($transition);

                    if (\array_key_exists('label', $meta)) {
                        return $this->translatableStringHelper->localize($meta['label']);
                    }

                    return $transition->getName();
                },
                'choice_attr' => static function (Transition $transition) use ($workflow) {
                    $toFinal = true;
                    $isForward = 'neutral';
                    $isSignature = [];
                    $isSentExternal = false;

                    $metadata = $workflow->getMetadataStore()->getTransitionMetadata($transition);

                    if (\array_key_exists('isForward', $metadata)) {
                        if ($metadata['isForward']) {
                            $isForward = 'forward';
                        } else {
                            $isForward = 'backward';
                        }
                    }

                    foreach ($transition->getTos() as $to) {
                        $meta = $workflow->getMetadataStore()->getPlaceMetadata($to);

                        if (
                            !\array_key_exists('isFinal', $meta) || false === $meta['isFinal']
                        ) {
                            $toFinal = false;
                        }

                        if (\array_key_exists('isSignature', $meta)) {
                            $isSignature = $meta['isSignature'];
                        }

                        $isSentExternal = $isSentExternal ? true : $meta['isSentExternal'] ?? false;
                    }

                    return [
                        'data-is-transition' => 'data-is-transition',
                        'data-to-final' => $toFinal ? '1' : '0',
                        'data-is-forward' => $isForward,
                        'data-is-signature' => json_encode($isSignature),
                        'data-is-sent-external' => $isSentExternal ? '1' : '0',
                    ];
                },
            ])
            ->add('isPersonOrUserSignature', ChoiceType::class, [
                'mapped' => false,
                'multiple' => false,
                'expanded' => true,
                'label' => 'workflow.signature_zone.type of signature',
                'choices' => [
                    'workflow.signature_zone.persons' => 'person',
                    'workflow.signature_zone.user' => 'user',
                ],
            ])
            ->add('futurePersonSignatures', PickPersonDynamicType::class, [
                'label' => 'workflow.signature_zone.person signatures',
                'multiple' => true,
                'empty_data' => '[]',
                'suggested' => $suggestedPersons,
            ])
            ->add('futureUserSignature', PickUserDynamicType::class, [
                'label' => 'workflow.signature_zone.user signature',
                'multiple' => false,
                'suggest_myself' => true,
                'suggested' => $suggestedUsers,
            ])
            ->add('futureDestUsers', PickUserGroupOrUserDynamicType::class, [
                'label' => 'workflow.dest for next steps',
                'multiple' => true,
                'empty_data' => '[]',
                'suggested' => $suggestedUsers,
                'suggest_myself' => true,
            ])
            ->add('futureCcUsers', PickUserDynamicType::class, [
                'label' => 'workflow.cc for next steps',
                'multiple' => true,
                'required' => false,
                'suggested' => $suggestedUsers,
                'empty_data' => '[]',
                'attr' => ['class' => 'future-cc-users'],
                'suggest_myself' => true,
            ])
            ->add('futureDestineeEmails', ChillCollectionType::class, [
                'entry_type' => EmailType::class,
                'entry_options' => [
                    'empty_data' => '',
                ],
                'allow_add' => true,
                'allow_delete' => true,
                'delete_empty' => static fn (?string $email) => '' === $email || null === $email,
                'button_add_label' => 'workflow.transition_destinee_add_emails',
                'button_remove_label' => 'workflow.transition_destinee_remove_emails',
                'help' => 'workflow.transition_destinee_emails_help',
                'label' => 'workflow.transition_destinee_emails_label',
            ])
            ->add('futureDestineeThirdParties', PickThirdpartyDynamicType::class, [
                'label' => 'workflow.transition_destinee_third_party',
                'help' => 'workflow.transition_destinee_third_party_help',
                'multiple' => true,
                'empty_data' => [],
                'suggested' => $suggestedThirdParties,
            ]);

        $builder
            ->add('comment', ChillTextareaType::class, [
                'required' => false,
                'label' => 'Comment',
                'empty_data' => '',
            ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver
            ->setDefault('data_class', WorkflowTransitionContextDTO::class)
            ->setRequired('entity_workflow')
            ->setAllowedTypes('entity_workflow', EntityWorkflow::class);
    }
}
