<?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\CompoundType;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * A relative period ("3 days", "50 weeks") as number + unit, the way the
 * settings screen edits every deadline. The model value stays the string
 * {@see PageConfig} stores and strtotime()/DateInterval understand; an empty
 * number means "not set" and maps to null.
 */
class PeriodType extends AbstractType
{
    private const UNIT_LABELS = [
        'hours' => 'Stunden',
        'days' => 'Tage',
        'weeks' => 'Wochen',
        'months' => 'Monate',
        'years' => 'Jahre',
    ];

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'units' => ['days', 'weeks', 'months'],
            'required' => false,
            'error_bubbling' => false,
        ]);

        $resolver->setAllowedTypes('units', 'string[]');
        $resolver->setAllowedValues('units', static fn (array $units) => [] !== $units && [] === array_diff($units, array_keys(self::UNIT_LABELS)));
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $units = $options['units'];

        $builder
            ->add('number', IntegerType::class, [
                'label' => false,
                'required' => false,
                'attr' => ['min' => 1, 'placeholder' => '—'],
            ])
            ->add('unit', ChoiceType::class, [
                'label' => false,
                'choices' => array_flip(array_intersect_key(self::UNIT_LABELS, array_flip($units))),
            ])
            ->addModelTransformer(new CallbackTransformer(
                static function (?string $period) use ($units): array {
                    if (null !== $period && preg_match('/^(\d+)\s+(\w+)$/', $period, $match)) {
                        return ['number' => (int) $match[1], 'unit' => $match[2]];
                    }

                    return ['number' => null, 'unit' => $units[0]];
                },
                static function (array $value): ?string {
                    $number = $value['number'] ?? null;
                    $unit = $value['unit'] ?? null;

                    return null !== $number && $number > 0 && null !== $unit ? $number.' '.$unit : null;
                },
            ))
        ;
    }

    public function getBlockPrefix(): string
    {
        return 'period';
    }
}
