<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\AdminBundle\Form\Builder;

use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfonycasts\DynamicForms\DependentField;

class DynamicFormBuilder extends \Symfonycasts\DynamicForms\DynamicFormBuilder
{
    /**
     * @var callable|null
     */
    private readonly mixed $readonly;

    public function __construct(private readonly FormBuilderInterface $builder, ?callable $readonly = null)
    {
        parent::__construct($builder);

        $builder->setAttribute(self::class, $this);

        // Dummy field for when condition does not depend on a particular field
        $builder->add('_', HiddenType::class, [
            'mapped' => false,
            'error_bubbling' => false,
        ]);

        $this->readonly = $readonly;
    }

    public static function fromBuilder(FormBuilderInterface $builder): ?self
    {
        return $builder->getAttribute(self::class);
    }

    public function add($child, ?string $type = null, array $options = []): static
    {
        $readonly = $this->readonly;
        if (\is_callable($readonly) && $readonly($child)) {
            $options = array_merge($options, ['disabled' => true]);
        }

        return parent::add($child, $type, $options);
    }

    public function addIf(string $name, string|array|null $dependencies = null, ?callable $condition = null, ?string $type = null, array $options = []): static
    {
        $readonly = $this->readonly;
        if (\is_callable($readonly) && $readonly($name)) {
            $options = array_merge($options, ['disabled' => true]);
        }

        // Fallback logic: all dependent fields must evaluate to true
        $condition ??= static fn (...$args): bool => \count($args) === \count(array_filter($args));

        $callback = function (DependentField $field, ...$args) use ($condition, $type, $options): void {
            if ($condition(...$args) && (!($options['section'] ?? null) || !$this->builder->hasOption('display_section') || !$this->builder->getOption('display_section') || $options['section'] === $this->builder->getOption('display_section'))) {
                $field->add($type, $options);
            }
        };

        $dependencies ??= '_';

        $this->addDependent($name, $dependencies, $callback);

        return $this;
    }
}
