<?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\CustomFieldsBundle\CustomFields;

use Chill\CustomFieldsBundle\Entity\CustomField;
use Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option;
use Chill\CustomFieldsBundle\EntityRepository\CustomFieldLongChoice\OptionRepository;
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldDataTransformer;
use Chill\MainBundle\Form\Type\Select2ChoiceType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;

class CustomFieldLongChoice extends AbstractCustomField
{
    final public const KEY = 'key';

    public function __construct(
        private readonly OptionRepository $optionRepository,
        private readonly TranslatableStringHelper $translatableStringHelper,
        private readonly \Twig\Environment $templating,
    ) {}

    public function buildForm(FormBuilderInterface $builder, CustomField $customField)
    {
        $options = $customField->getOptions();
        $entries = $this->optionRepository->findFilteredByKey(
            $options[self::KEY],
            false,
            true
        );
        // create a local copy of translatable string helper
        $translatableStringHelper = $this->translatableStringHelper;
        $builder->add($customField->getSlug(), Select2ChoiceType::class, [
            'choices' => $entries,
            'choice_label' => static fn (?Option $option) => $translatableStringHelper->localize($option->getText()),
            'choice_value' => static fn (?Option $key): ?int => $key?->getId(),
            'multiple' => false,
            'expanded' => false,
            'required' => $customField->isRequired(),
            'placeholder' => 'Choose a value',
            'group_by' => static function (Option $option) use ($translatableStringHelper) {
                if ($option->hasParent()) {
                    return $translatableStringHelper->localize($option->getParent()->getText());
                }

                return $translatableStringHelper->localize($option->getText());
            },
            'label' => $translatableStringHelper->localize($customField->getName()),
        ]);

        $builder
            ->get($customField->getSlug())
            ->addModelTransformer(new CustomFieldDataTransformer($this, $customField));
    }

    public function buildOptionsForm(FormBuilderInterface $builder)
    {
        // create a selector between different keys
        $keys = $this->optionRepository->getKeys();
        $choices = [];

        foreach ($keys as $key) {
            $choices[$key] = $key;
        }

        return $builder->add(self::KEY, ChoiceType::class, [
            'choices' => array_combine(array_values($choices), array_keys($choices)),
            'label' => 'Options key',
        ]);
    }

    public function deserialize($serialized, CustomField $customField)
    {
        if (null === $serialized) {
            return null;
        }

        return $this->optionRepository->find($serialized);
    }

    public function getName()
    {
        return 'Long choice field';
    }

    public function render($value, CustomField $customField, $documentType = 'html')
    {
        $option = $this->deserialize($value, $customField);
        $template = '@ChillCustomFields/CustomFieldsRendering/choice_long.'
                .$documentType.'.twig';

        return $this->templating
            ->render($template, [
                'values' => null === $option ? [] : [$option],
            ]);
    }

    public function serialize($value, CustomField $customField)
    {
        if (null === $value) {
            return null;
        }

        if (!$value instanceof Option) {
            throw new \LogicException('the value should be an instance of Chill\CustomFieldsBundle\Entity\CustomFieldLongChoice\Option, '.\is_object($value) ? $value::class : \gettype($value).' given');
        }

        // we place the id in array, to allow in the future multiple select
        return $value->getId();
    }
}
