<?php
/**
 * Copyright since 2025 InPost S.A.
 *
 * For the full license information, please view the LICENSE file bundled with the module.
 *
 * @author InPost S.A.
 * @copyright since 2025 InPost S.A.
 * @license MIT
 */

declare(strict_types=1);

namespace InPost\International\PickupOrder\Form;

use Doctrine\ORM\EntityRepository;
use InPost\International\Common\Form\Type\ReferenceType;
use InPost\International\Entity\PickupAddress;
use InPost\International\PickupOrder\Message\CreatePickupOrderCommand;
use InPost\International\PickupOrder\Util\CutoffPickupTimeChecker;
use PrestaShopBundle\Form\Admin\Type\DatePickerType;
use Psr\Clock\ClockInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
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\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\GreaterThanOrEqual;
use Symfony\Contracts\Translation\TranslatorInterface;

if (!defined('_PS_VERSION_')) {
    exit;
}

final class PickupOrderType extends AbstractType
{
    /**
     * @var TranslatorInterface
     */
    private $translator;

    /**
     * @var CutoffPickupTimeChecker
     */
    private $cutoffTimeChecker;

    /**
     * @var ClockInterface
     */
    private $clock;

    public function __construct(TranslatorInterface $translator, CutoffPickupTimeChecker $cutoffTimeChecker, ClockInterface $clock)
    {
        $this->translator = $translator;
        $this->cutoffTimeChecker = $cutoffTimeChecker;
        $this->clock = $clock;
    }

    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $builder
            ->add('shipmentIds', CollectionType::class, [
                'allow_add' => true,
                'entry_type' => HiddenType::class,
                'label' => false,
            ])
            ->add('pickupAddress', EntityType::class, [
                'class' => PickupAddress::class,
                'query_builder' => static function (EntityRepository $repository) {
                    return $repository
                        ->createQueryBuilder('a')
                        ->where('a.deleted = 0');
                },
                'label' => $this->translator->trans('Pickup address', [], 'Modules.Inpostinternational.Pickup'),
                'attr' => [
                    'class' => 'js-pickup-address-choice',
                    'autocomplete' => 'off',
                ],
            ])
            ->add('pickupDate', DatePickerType::class, [
                'label' => $this->translator->trans('Pickup date', [], 'Modules.Inpostinternational.Pickup'),
                'constraints' => new GreaterThanOrEqual($this->clock->now()->setTime(0, 0)),
            ])
            ->add('pickupTime', PickupTimeType::class, [
                'label' => $this->translator->trans('Pickup time', [], 'Modules.Inpostinternational.Pickup'),
            ])
            ->add('references', CollectionType::class, [
                'entry_type' => ReferenceType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
                'required' => false,
                'label' => $this->translator->trans('References', [], 'Modules.Inpostinternational.Pickup'),
                'block_prefix' => 'dynamic_collection',
            ])
            ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
                $data = $event->getData();

                if (!$data instanceof CreatePickupOrderCommand || null === $address = $data->getPickupAddress()) {
                    return;
                }

                $this->limitMaxPickupTime($event->getForm(), $address);
            });

        $builder->get('pickupAddress')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) {
            $form = $event->getForm();
            $data = $form->getData();

            if (!$data instanceof PickupAddress) {
                return;
            }

            $this->limitMaxPickupTime($form->getParent(), $data);
        });

        $builder->get('pickupDate')
            ->addModelTransformer(new DateTimeImmutableToDateTimeTransformer())
            ->addViewTransformer(new DateTimeToStringTransformer(null, null, 'Y-m-d'), true);

        $builder->get('shipmentIds')->addModelTransformer(new CallbackTransformer(
            static function ($shipmentIds) {
                return $shipmentIds;
            },
            static function (array $shipmentIds) {
                return array_map('intval', $shipmentIds);
            }
        ));
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class' => CreatePickupOrderCommand::class,
        ]);
    }

    private function limitMaxPickupTime(FormInterface $form, PickupAddress $address): void
    {
        if (null === $cutoffTime = $this->cutoffTimeChecker->check($address)) {
            return;
        }

        $form->add('pickupTime', PickupTimeType::class, [
            'cutoff_time' => $cutoffTime,
            'label' => $this->translator->trans('Pickup time', [], 'Modules.Inpostinternational.Pickup'),
        ]);
    }
}
