<?php

declare(strict_types=1);

namespace Gls\GlsPoland\Form\Type;

use Gls\GlsPoland\Carrier\CarrierType;
use Gls\GlsPoland\Consignment\DTO\AddressDetails;
use Gls\GlsPoland\Form\DataTransformer\DateTimeImmutableToDateTimeTransformer;
use Gls\GlsPoland\Message\CreateConsignmentCommand;
use Gls\GlsPoland\Translation\TranslatorAwareTrait;
use PrestaShopBundle\Form\Admin\Type\DatePickerType;
use Symfony\Component\Form\AbstractType;
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\Extension\Core\Type\TextType;
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\Constraint;

final class CreateConsignmentType extends AbstractType
{
    use TranslatorAwareTrait;

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

        $builder
            ->add('orderId', HiddenType::class, [
                'mapped' => false,
            ])
            ->add('type', CarrierTypeChoiceType::class, [
                'mapped' => false,
                'label' => $this->getTranslator()->trans('Consignment type', [], 'Modules.Glspoland.Consignment'),
                'data' => $data instanceof CreateConsignmentCommand ? (string) $data->getServiceDetails()->getCarrierType() : null,
            ])
            ->add('recipientDetails', AddressDetailsType::class, [
                'label' => $this->getTranslator()->trans('Recipient details', [], 'Modules.Glspoland.Consignment'),
            ])
            ->add('references', TextType::class, [
                'required' => false,
                'label' => $this->getTranslator()->trans('References', [], 'Modules.Glspoland.Consignment'),
            ])
            ->add('notes', TextType::class, [
                'required' => false,
                'label' => $this->getTranslator()->trans('Notes', [], 'Modules.Glspoland.Consignment'),
            ])
            ->add('shippingDate', DatePickerType::class, [
                'required' => false,
                'label' => $this->getTranslator()->trans('Shipping date', [], 'Modules.Glspoland.Consignment'),
            ])
            ->add('parcels', CollectionType::class, [
                'entry_type' => ParcelType::class,
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,
                'label' => $this->getTranslator()->trans('Parcels', [], 'Modules.Glspoland.Consignment'),
            ])
            ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
                $form = $event->getForm();
                $data = $event->getData();

                if ($data instanceof CreateConsignmentCommand) {
                    $isShopDelivery = $data->getServiceDetails()->isShopDelivery();
                    $domestic = 'PL' === $data->getRecipientDetails()->getCountryIsoCode();
                } else {
                    $isShopDelivery = false;
                    $domestic = false;
                }

                $this->addServiceDetailsField($form, $domestic, $isShopDelivery);
            })
            ->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
                $form = $event->getForm();
                $data = $event->getData();

                $isShopDelivery = CarrierType::SHOP_DELIVERY === ($data['type'] ?? null);

                $this->addServiceDetailsField($form, 'PL' === ($data['recipientDetails']['countryIsoCode'] ?? null), $isShopDelivery);
            });

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

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver
            ->setDefaults([
                'data_class' => CreateConsignmentCommand::class,
                'empty_data' => function (FormInterface $form): CreateConsignmentCommand {
                    $orderId = (int) $form->get('orderId')->getData();
                    $recipientDetails = $form->get('recipientDetails')->getData();

                    return new CreateConsignmentCommand($orderId, $recipientDetails);
                },
                'validation_groups' => static function (FormInterface $form) {
                    /** @var CreateConsignmentCommand $data */
                    $data = $form->getData();

                    $groups = [Constraint::DEFAULT_GROUP, AddressDetails::OTHER_ADDRESS_VALIDATION_GROUP];
                    if ($data->getServiceDetails()->isShopDelivery()) {
                        $groups[] = AddressDetails::CONTACT_INFO_VALIDATION_GROUP;
                    }

                    return $groups;
                },
            ]);
    }

    private function addServiceDetailsField(FormInterface $form, bool $domestic, bool $shopDelivery): void
    {
        if ($shopDelivery) {
            $type = ShopDeliveryServiceDetailsType::class;
        } else {
            $type = CourierServiceDetailsType::class;
        }

        $form->add('serviceDetails', $type, [
            'label' => false,
        ]);
    }
}
