<?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\Type\Export;

use Chill\MainBundle\Export\ExportManager;
use Chill\MainBundle\Export\SortExportElement;
use Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class ExportType extends AbstractType
{
    final public const AGGREGATOR_KEY = 'aggregators';

    final public const EXPORT_KEY = 'export';

    final public const FILTER_KEY = 'filters';

    final public const PICK_FORMATTER_KEY = 'pick_formatter';

    private array $personFieldsConfig;

    public function __construct(
        private readonly ExportManager $exportManager,
        private readonly SortExportElement $sortExportElement,
        ParameterBagInterface $parameterBag,
    ) {
        $this->personFieldsConfig = $parameterBag->get('chill_person.person_fields');
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $export = $this->exportManager->getExport($options['export_alias']);
        /** @var bool $canEditFull */
        $canEditFull = $options['can_edit_full'];

        $exportOptions = [
            'compound' => true,
            'constraints' => [
            ],
        ];

        // add a contraint if required by export
        $exportBuilder = $builder->create(self::EXPORT_KEY/* , FormType::class, $exportOptions */);

        $export->buildForm($exportBuilder);

        $builder->add($exportBuilder, null, $exportOptions);

        if ($export instanceof \Chill\MainBundle\Export\ExportInterface) {
            // add filters
            $filterAliases = $options['allowed_filters'];
            $filters = [];
            if (is_iterable($filterAliases)) {
                foreach ($filterAliases as $alias => $filter) {
                    $filters[$alias] = $filter;
                }
            } else {
                $filters = $this->exportManager->getFiltersApplyingOn($export, $options['picked_centers']);
            }

            $this->sortExportElement->sortFilters($filters);

            $filterBuilder = $builder->create(self::FILTER_KEY, FormType::class, ['compound' => true]);

            foreach ($filters as $alias => $filter) {
                $filterBuilder->add($alias, FilterType::class, [
                    'filter' => $filter,
                    'label' => $filter->getTitle(),
                    'constraints' => [
                        new ExportElementConstraint(['element' => $filter]),
                    ],
                    'disable_enable_field' => !$canEditFull,
                ]);
            }

            $builder->add($filterBuilder);

            // add aggregators
            $aggregatorsAliases = $options['allowed_aggregators'];
            $aggregators = [];
            if (is_iterable($aggregatorsAliases)) {
                foreach ($aggregatorsAliases as $alias => $aggregator) {
                    $aggregators[$alias] = $aggregator;
                }
            } else {
                $aggregators = $this->exportManager
                    ->getAggregatorsApplyingOn($export, $options['picked_centers']);
            }

            $this->sortExportElement->sortAggregators($aggregators);

            $aggregatorBuilder = $builder->create(
                self::AGGREGATOR_KEY,
                FormType::class,
                ['compound' => true]
            );

            foreach ($aggregators as $alias => $aggregator) {
                /*
                 * eventually mask aggregator
                 */
                if (str_starts_with((string) $alias, 'person_') and str_ends_with((string) $alias, '_aggregator')) {
                    $field = preg_replace(['/person_/', '/_aggregator/'], '', (string) $alias);
                    if (array_key_exists($field, $this->personFieldsConfig) and 'visible' !== $this->personFieldsConfig[$field]) {
                        continue;
                    }
                }

                $aggregatorBuilder->add($alias, AggregatorType::class, [
                    'aggregator_alias' => $alias,
                    'export_manager' => $this->exportManager,
                    'label' => $aggregator->getTitle(),
                    'disable_enable_field' => !$canEditFull,
                    'constraints' => [
                        new ExportElementConstraint(['element' => $aggregator]),
                    ],
                ]);
            }

            $builder->add($aggregatorBuilder);
        }

        // add export form
        $exportBuilder = $builder->create(self::EXPORT_KEY, FormType::class, ['compound' => true]);
        $this->exportManager->getExport($options['export_alias'])
            ->buildForm($exportBuilder);
        $builder->add($exportBuilder);

        if ($export instanceof \Chill\MainBundle\Export\ExportInterface) {
            $builder->add(self::PICK_FORMATTER_KEY, PickFormatterType::class, [
                'export_alias' => $options['export_alias'],
            ]);
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(['export_alias', 'picked_centers', 'can_edit_full'])
            ->setAllowedTypes('export_alias', ['string'])
            ->setAllowedValues('can_edit_full', [true, false])
            ->setDefault('allowed_filters', null)
            ->setAllowedTypes('allowed_filters', ['iterable', 'null'])
            ->setDefault('allowed_aggregators', null)
            ->setAllowedTypes('allowed_aggregators', ['iterable', 'null'])
            ->setDefault('compound', true)
            ->setDefault('constraints', [
                // new \Chill\MainBundle\Validator\Constraints\Export\ExportElementConstraint()
            ]);
    }

    public function getParent()
    {
        return FormType::class;
    }
}
