<?php

namespace AutoAdmin\Bundle\Admin\Form\Type;

use AutoAdmin\Bundle\Admin\Configuration\ConfigManager as AdminConfigManager;
use AutoAdmin\Bundle\Admin\Form\Type\Component\RichSelect;
use AutoAdmin\Bundle\Content\Configuration\ConfigManager;
use AutoAdmin\Bundle\Content\Entity\ContentReference;
use AutoAdmin\Bundle\Content\Entity\Locale;
use AutoAdmin\Bundle\Content\Model\ContentInterface;
use Doctrine\Persistence\ManagerRegistry;
use Exception;
use Psr\Log\LoggerInterface;
use ReflectionClass;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ContentReferenceType extends AbstractType
{
    protected array $contentTypeChoices = [];
    protected array $localeChoices = [];
    protected ConfigManager $configManager;
    protected AdminConfigManager $adminConfigManager;
    protected ManagerRegistry $doctrine;
    private LoggerInterface $logger;

    public function __construct(
        ConfigManager      $configManager,
        AdminConfigManager $adminConfigManager,
        ManagerRegistry    $doctrine,
        LoggerInterface    $logger
    )
    {
        $this->configManager = $configManager;
        $this->adminConfigManager = $adminConfigManager;
        $this->doctrine = $doctrine;
        $this->logger = $logger;

        $config = $adminConfigManager->getConfig('entities');
        foreach ($config as $item) {
            $refl = new ReflectionClass($item['class']);
            try {
                if (
                    ($frontCfg = $this->configManager->getContentConfigForFqdn($item['class']))
                    && $refl->implementsInterface(ContentInterface::class)
                    && $frontCfg['slug'] !== null
                ) {
                    $this->contentTypeChoices[$item['name'] ?? $frontCfg['slug']] = $frontCfg['slug'];
                }
            } catch (Exception $e) {
                $this->logger->log('warning', 'ContentReference exception:' . $e->getMessage());
            }
        }

        $localeRepo = $doctrine->getRepository(Locale::class);
        /** @var Locale[] $locales */
        $locales = $localeRepo->findAll();
        $this->localeChoices['auto'] = null;
        foreach ($locales as $locale) {
            $this->localeChoices[$locale->getCode()] = $locale->getId();
        }
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults(
            [
                'data_class' => ContentReference::class,
                'allowed_slugs' => [
//                    used to filter allowed entity slugs, example:
//                    'page',
                ],
            ]
        );
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $contentTypeChoices = $this->contentTypeChoices;
        if (!empty($options['allowed_slugs'])) {
            $contentTypeChoices = array_intersect($this->contentTypeChoices, $options['allowed_slugs']);
        }

        $builder->add(
            'referenced_slug',
            RichSelect::class,
            [
                'choices' => $contentTypeChoices,
                'attr' => ['class' => 'aa-content-ref-slug'],
                'label' => 'content_reference.referenced_slug',
            ]
        );
        $builder->add(
            'search_results',
            RichSelect::class,
            [
                'mapped' => false,
                'attr' => [
                    'class' => 'aa-content-ref-search-results',
                ],
                'label' => 'content_reference.search_results',
            ]
        );

        $builder->add(
            'id',
            HiddenType::class,
            [
                'attr' => ['class' => 'aa-content-ref-pk'],
            ]
        );

        $builder->add(
            'referenced_action',
            HiddenType::class,
            [
                'mapped' => false,// we do not use action for now, field will be mapped later
                'attr' => ['class' => 'aa-content-ref-action'],
            ]
        );

        $builder->add(
            'referenced_identifier',
            HiddenType::class,
            [
                'attr' => ['class' => 'aa-content-ref-id'],
            ]
        );

        // at least: null + auto + default_lang(often "fr")
        $defaultOpts = [
            'empty_data' => null,
            'attr' => ['class' => 'aa-content-ref-locale'],
        ];
        if (empty($this->localeChoices) && count($this->localeChoices) > 3) {
            $builder->add(
                'referenced_locale',
                RichSelect::class,
                array_merge(
                    $defaultOpts,
                    [

                        'choices' => $this->localeChoices,
                        'label' => 'content_reference.referenced_locale',
                    ]
                )
            );
        } else {
            $builder->add('referenced_locale', HiddenType::class, array_merge($defaultOpts, []));
        }

        // add delete field if we have an entity
        $builder->addEventListener(
            FormEvents::POST_SET_DATA,
            function (FormEvent $event) {
                if (($data = $event->getData()) && $data instanceof ContentReference) {
                    // add remove checkbox
                    if ($data->getId()) {
                        $event->getForm()->add(
                            'pending_delete',
                            CheckboxType::class,
                            [
                                'attr' => ['class' => 'aa-content-ref-delete'],
                                'label' => 'content_reference.pending_delete',
                            ]
                        );
                    }
                }
            }
        );

        // we are not allowed to post unknown "choices" values in search_results value (validation error),
        // so delete the posted index as we don't need it
        $builder->addEventListener(
            FormEvents::PRE_SUBMIT,
            function (FormEvent $event) {
                $data = $event->getData();
                unset($data['search_results']);
                $event->setData($data);
            }
        );

        $builder->addEventListener(
            FormEvents::SUBMIT,
            function (FormEvent $event) {
                $data = $event->getData();
                if (empty($data)) {
                    return;
                }

                if ($data instanceof ContentReference
                    && (
                        empty($data->getReferencedIdentifier())
                        || empty($data->getReferencedSlug())
                    )
                ) {
                    $data = null;
                    $event->setData($data);
                }
            }
        );
    }

    public function buildView(FormView $view, FormInterface $form, array $options): void
    {
        $class = 'aa-content-reference';
        $view->vars['attr'] = array_merge(
            $view->vars['attr'],
            [
                'class' => ($view->vars['attr']['class'] ?? '') . ' ' . $class,
            ]
        );
    }
}
