<?php

namespace AutoAdmin\Bundle\Admin\Form\Type;

use AutoAdmin\Bundle\Admin\Configuration\ConfigManager;
use AutoAdmin\Bundle\Admin\Form\FormOptionNormalizer;
use AutoAdmin\Bundle\Admin\Form\Type\Component\RichEntityType;
use AutoAdmin\Bundle\Admin\Helper\AccessHelper;
use AutoAdmin\Bundle\Core\Logic\LogicTester;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class AdminContentType extends AbstractType
{
    public function __construct(
        protected ConfigManager $configManager,
        protected FormOptionNormalizer $formOptionNormalizer,
        protected AccessHelper $accessHelper,
        protected LogicTester $logicTester,
    ) {
    }

    public function getParent(): string
    {
        return AdminFormType::class;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $class = $options['data_class'];
        $entityAction = $options['entity_action'];
        $entityConfig = $this->configManager->getEntityConfigByClass($class);
        $fields = $entityConfig['form'][$entityAction][$options['admin_tab'] ?? 'default'] ?? [];

        foreach ($fields as $k => $field) {
            if (!empty($field['roles']) && $this->accessHelper->isGranted($field['roles']) === false) {
                continue;
            }

            /*
             * Used in yaml config for form fields in AA admin using following format:
             * - { if: '_.static = false AND id = 611', property: '_tr.name', label: "ConditionalName" }
             */
            if (
                ($if = $field['if'])
                && ($data = $builder->getData())
            ) {
                $state = $this->logicTester->test($if, $data);
                if ($state === false) {
                    // we skip this dynamically conditioned field
                    continue;
                }
            }

            $prop = $field['property'];


            $field['property'] = str_replace('_tr.', '', $prop);
            $formTypeOptions = $this->formOptionNormalizer->normalize($field['type_options']);
            $formTypeOptions = array_merge([
                'property_path' => str_replace('_tr.', 'currentTranslation.', $prop),
                'priority' => $field['priority'] ?? 0,
                'translation_domain' => $field['translation_domain'] ?? 'aa_admin',
            ], $formTypeOptions);

            // override default choice label
            if ($field['type'] == RichEntityType::class && $field['choice_label']) {
                $formTypeOptions = $this->setChoiceLabel($field, $formTypeOptions);
            }

            // if we have a dot we probably have a translation key and want to translate through symfony forms
            if (!empty($field['label']) && strpos($field['label'], '.')) {
                $formTypeOptions['label'] = $field['label'];
            }

            $builder->add($field['property'], $field['type'], $formTypeOptions);
        }

        if ($options['has_submit']) {
            $builder->add('submit', SubmitType::class, ['label' => 'save',]);
            if (empty($options['disable_submit_and_return'])) {
                $builder->add('submit_and_return', SubmitType::class, ['label' => 'save_and_return',]);
            }
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefined('em');
        $resolver->setDefined('query_builder');
        $resolver->setDefault('label', false);
        $resolver->setDefault('has_submit', false);
        $resolver->setDefault('admin_tab', 'default');
        $resolver->setDefault('entity_action', 'update');
    }

    /**
     * @param mixed $field
     * @param array $formTypeOptions
     * @return array
     */
    public function setChoiceLabel(mixed $field, array $formTypeOptions): array
    {
        $formTypeOptions['choice_label'] = function ($choice, $key, $value) use ($field) {
            $choiceObject = clone $choice;

            if (str_contains($field['choice_label'], '_tr.')) {
                $choiceObject = $choice->getCurrentTranslation() ? $choice->getCurrentTranslation() : $choice;
                $field['choice_label'] = str_replace('_tr.', '', $field['choice_label']);
            }

            if (!str_starts_with($field['choice_label'], 'get')) {
                $methodName = 'get'.ucfirst($field['choice_label']);
            } else {
                $methodName = $field['choice_label'];
            }

            if (method_exists($choiceObject, $methodName)) {
                return $choiceObject->{$methodName}();
            } else {
                return $choice;
            }
        };

        return $formTypeOptions;
    }
}
