<?php

namespace Mautic\FormBundle\Tests\Controller;

use Mautic\AssetBundle\Entity\Asset;
use Mautic\CategoryBundle\Entity\Category;
use Mautic\CoreBundle\Helper\LanguageHelper;
use Mautic\CoreBundle\Test\MauticMysqlTestCase;
use Mautic\EmailBundle\Entity\Email;
use Mautic\FormBundle\Entity\Action;
use Mautic\FormBundle\Entity\Field;
use Mautic\FormBundle\Entity\Form;
use Mautic\LeadBundle\Entity\LeadField;
use Mautic\LeadBundle\Entity\LeadList;
use Mautic\ProjectBundle\Entity\Project;
use PHPUnit\Framework\Assert;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;

class FormControllerFunctionalTest extends MauticMysqlTestCase
{
    protected $useCleanupRollback = false;

    protected function setUp(): void
    {
        parent::setUp();

        if ('testLabelsForFormAction' === $this->name()) {
            $this->truncateTables('assets', 'categories', 'emails', 'lead_lists');
        }
    }

    /**
     * Index should return status code 200.
     */
    public function testIndexActionWhenNotFiltered(): void
    {
        $this->client->request('GET', '/s/forms');
        $this->assertTrue($this->client->getResponse()->isOk());
    }

    /**
     * Filtering should return status code 200.
     */
    public function testIndexActionWhenFiltering(): void
    {
        $this->client->request('GET', '/s/forms?search=has%3Aresults&tmpl=list');
        $this->assertTrue($this->client->getResponse()->isOk());
    }

    /**
     * Get form's create page.
     */
    public function testNewActionForm(): void
    {
        $this->client->request('GET', '/s/forms/new/');
        $this->assertTrue($this->client->getResponse()->isOk());
    }

    /**
     * @see https://github.com/mautic/mautic/issues/10453
     */
    public function testSaveActionForm(): void
    {
        $crawler = $this->client->request('GET', '/s/forms/new/');
        $this->assertTrue($this->client->getResponse()->isOk());

        $form = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $form->setValues(
            [
                'mauticform[name]'        => 'Test',
                'mauticform[renderStyle]' => '0',
            ]
        );
        $crawler = $this->client->submit($form);
        $this->assertTrue($this->client->getResponse()->isOk());

        $form = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $form->setValues(
            [
                'mauticform[renderStyle]' => '0',
            ]
        );

        // The form failed to save when saved for the second time with renderStyle=No.
        $this->client->submit($form);
        $this->assertTrue($this->client->getResponse()->isOk(), $this->client->getResponse()->getContent());
        $this->assertStringNotContainsString('Internal Server Error - Expected argument of type "null or string", "boolean" given', $this->client->getResponse()->getContent());
    }

    public function testNewActionCheckDisplayMessageOptionsForm(): void
    {
        $this->client->request('GET', '/s/forms/new');
        $this->assertTrue($this->client->getResponse()->isOk());
        $clientResponse = $this->client->getResponse();
        self::assertResponseStatusCodeSame(Response::HTTP_OK, $clientResponse->getContent());
        $this->assertStringContainsString('Hide form', $clientResponse->getContent(), $clientResponse->getContent());
        $this->assertStringContainsString('Redirect URL', $clientResponse->getContent(), $clientResponse->getContent());
        $this->assertStringContainsString('Remain at form', $clientResponse->getContent(), $clientResponse->getContent());
    }

    public function testErrorValidationWithHideFormTypeWithoutMessage(): void
    {
        $crawler = $this->client->request('GET', '/s/forms/new/');
        $this->assertTrue($this->client->getResponse()->isOk());

        $selectedValue = $crawler->filter('#mauticform_postAction option:selected')->attr('value');

        $this->assertEquals('message', $selectedValue);

        $form = $crawler->filterXPath('//form[@name="mauticform"]')->form();

        $form->setValues(
            [
                'mauticform[name]'       => 'Test',
                'mauticform[postAction]' => 'hideform',
            ]
        );

        $crawler = $this->client->submit($form);
        $this->assertTrue($this->client->getResponse()->isOk());
        $divClass = $crawler->filter('#mauticform_postActionProperty')->ancestors()->first()->attr('class');
        $this->assertStringContainsString('has-error', $divClass, $crawler->html());
    }

    public function testSuccessWithHideForm(): void
    {
        $crawler = $this->client->request('GET', '/s/forms/new/');
        $this->assertTrue($this->client->getResponse()->isOk());

        $selectedValue = $crawler->filter('#mauticform_postAction option:selected')->attr('value');

        $this->assertEquals('message', $selectedValue);

        $form = $crawler->filterXPath('//form[@name="mauticform"]')->form();

        $form->setValues(
            [
                'mauticform[name]'               => 'Test',
                'mauticform[postAction]'         => 'hideform',
                'mauticform[postActionProperty]' => 'message',
            ]
        );
        $crawler = $this->client->submit($form);
        $this->assertTrue($this->client->getResponse()->isOk(), $this->client->getResponse()->getContent());
        $divClass = $crawler->filter('#mauticform_postActionProperty')->ancestors()->first()->attr('class');
        $this->assertStringNotContainsString('has-error', $divClass, $crawler->html());
    }

    public function testLanguageForm(): void
    {
        $translationsPath = __DIR__.'/resource/language/fr';
        $languagePath     = __DIR__.'/../../../../../translations/fr';
        $filesystem       = new Filesystem();

        // copy all from $translationsPath to $languagePath
        $filesystem->mirror($translationsPath, $languagePath);

        /** @var LanguageHelper $languageHelper */
        $languageHelper = $this->getContainer()->get('mautic.helper.language');

        $formPayload = [
            'name'       => 'Test Form',
            'formType'   => 'campaign',
            'language'   => 'fr',
            'postAction' => 'return',
            'fields'     => [
                [
                    'label'      => 'Email',
                    'alias'      => 'email',
                    'type'       => 'email',
                    'leadField'  => 'email',
                    'isRequired' => true,
                ], [
                    'label' => 'Submit',
                    'alias' => 'submit',
                    'type'  => 'button',
                ],
            ],
        ];
        $this->client->request('POST', '/api/forms/new', $formPayload);
        $clientResponse = $this->client->getResponse();
        $response       = json_decode($clientResponse->getContent(), true);
        $this->assertSame(Response::HTTP_CREATED, $clientResponse->getStatusCode(), json_encode($languageHelper->getLanguageChoices()));
        $form     = $response['form'];
        $formId   = $form['id'];

        $crawler = $this->client->request('GET', '/form/'.$form['id']);
        $this->assertStringContainsString('Merci de patienter...', $crawler->html());
        $this->assertStringContainsString('Ceci est requis.', $crawler->html());

        $filesystem->remove($languagePath);
    }

    public function testMappedFieldIsNotMarkedAsRemappedUponSavingTheForm(): void
    {
        $form  = $this->createForm('Test', 'test');
        $field = $this->createFormField([
            'label'        => 'Email',
            'type'         => 'email',
        ])->setForm($form);

        // @phpstan-ignore-next-line (using the deprecated method on purpose)
        $field->setLeadField('email');
        $this->em->persist($field);
        $this->em->flush();
        $this->em->clear();

        $crawler = $this->client->request('GET', sprintf('/s/forms/edit/%d', $form->getId()));
        $this->assertTrue($this->client->getResponse()->isOk());

        $formElement = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $this->client->submit($formElement);
        $response = $this->client->getResponse();
        $this->assertTrue($response->isOk());
        $this->assertStringNotContainsString('contact: Email', $response->getContent(), 'Email field should not be marked as mapped.');
    }

    public function testMappedFieldIsNotAutoFilledWhenUpdatingField(): void
    {
        $form  = $this->createForm('Test', 'test');
        $field = $this->createFormField([
            'label' => 'Email',
            'type'  => 'email',
        ])->setForm($form);
        $field->setMappedObject(null);
        $field->setMappedField(null);
        $this->em->persist($field);
        $this->em->flush();
        $this->em->clear();

        $crawler = $this->client->request('GET', sprintf('/s/forms/edit/%d', $form->getId()));
        $this->assertTrue($this->client->getResponse()->isOk(), $this->client->getResponse()->getContent());

        $formElement = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $this->client->submit($formElement);
        $this->assertTrue($this->client->getResponse()->isOk());

        $this->client->xmlHttpRequest('GET', sprintf('/s/forms/field/edit/%d?formId=%d', $field->getId(), $form->getId()));
        $response = $this->client->getResponse();
        $this->assertTrue($response->isOk());
        $this->assertJson($response->getContent());

        $content = json_decode($response->getContent())->newContent;
        $crawler = new Crawler($content, $this->client->getInternalRequest()->getUri());
        $options = $crawler->filterXPath('//select[@name="formfield[mappedField]"]')->html();
        $this->assertStringContainsString('<option value="email">Email</option>', $options, 'Email option should not be pre-selected.');
    }

    public function testMappedFieldCheckboxGroup(): void
    {
        // Create custom boolean field.
        $customField = new LeadField();
        $customField->setObject('lead');
        $customField->setType('boolean');
        $customField->setLabel('Custom Bool Field');
        $customField->setAlias('custom_boolean_field');
        $customField->setProperties([
            'yes' => 'Absolutely yes',
            'no'  => 'Obviously No',
        ]);

        // Create & add checkbox group type field to form.
        $form  = $this->createForm('Test form', 'test_form');
        $field = $this->createFormField([
            'label' => 'Test Checkbox Group',
            'type'  => 'checkboxgrp',
        ]);
        $field->setMappedObject('contact');
        $field->setMappedField('custom_boolean_field');
        $fieldProperties = [
            'list' => [
                'option1' => 'First Option',
                'option2' => 'Second Option',
            ],
        ];
        $field->setProperties($fieldProperties);
        $field->setForm($form);
        $this->em->persist($field);
        $this->em->flush();
        $this->em->clear();

        // Verify form creation
        $crawler = $this->client->request('GET', sprintf('/s/forms/edit/%d', $form->getId()));
        $this->assertResponseIsSuccessful();

        // Visit the form preview page
        $crawler = $this->client->request('GET', sprintf('/s/forms/preview/%d', $form->getId()));
        $this->assertResponseIsSuccessful();
        $this->assertStringContainsString('First Option', $this->client->getResponse()->getContent());
        $this->assertStringContainsString('Second Option', $this->client->getResponse()->getContent());
    }

    public function testCreateNewActionUsingBaseTemplateToDisplay(): void
    {
        // Create new form
        $form = $this->createForm('Test', 'test');
        $this->em->persist($form);

        // Fetch the form
        $this->client->xmlHttpRequest(Request::METHOD_GET, '/s/forms/action/new',
            [
                'formId' => $form->getId(),
                'type'   => 'lead.addutmtags',
            ]
        );
        $this->assertResponseIsSuccessful();
        $content     = $this->client->getResponse()->getContent();
        $content     = json_decode($content)->newContent;
        $crawler     = new Crawler($content, $this->client->getInternalRequest()->getUri());
        $formCrawler = $crawler->filter('form');
        $this->assertCount(1, $formCrawler);
        $form = $formCrawler->form();

        // Save new Send Form Results action
        $this->client->submit($form);
        $this->assertResponseIsSuccessful();
        $content    = $this->client->getResponse()->getContent();
        $actionHtml = json_decode($content, true)['actionHtml'] ?? null;
        $this->assertNotNull($actionHtml, $content);
        $crawler  = new Crawler($actionHtml);
        $editPage = $crawler->filter('.btn-edit')->attr('href');

        // Check the content was not changed
        $this->client->xmlHttpRequest(Request::METHOD_GET, $editPage);
        $this->assertResponseIsSuccessful();
    }

    public function testEditNewActionUsingBaseTemplateToDisplay(): void
    {
        // Create new form
        $form = $this->createForm('Test', 'test');

        // Create action
        $action = $this->createFormAction($form, 'lead.addutmtags');
        $form->addAction(0, $action);
        $this->em->persist($form);

        $this->em->flush();
        $this->em->clear();

        // Edit and submit the form to be able to push action into session
        $crawler     = $this->client->request('GET', sprintf('/s/forms/edit/%d', $form->getId()));
        $formElement = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $this->client->submit($formElement);
        $this->assertResponseIsSuccessful();

        // Update the Action
        $this->setCsrfHeader();
        $this->client->setServerParameter('HTTP_X-Requested-With', 'XMLHttpRequest');
        $this->client->xmlHttpRequest(
            Request::METHOD_POST,
            sprintf('/s/forms/action/edit/%s?formId=%s', $action->getId(), $form->getId()),
            ['formId' => $form->getId()], // Query parameters (handled in URL)
            [], // Files
            ['CONTENT_TYPE' => 'application/json'], // server
            json_encode([
                'formaction' => [
                    'id'          => $action->getId(),
                    'name'        => $action->getName(),
                    'type'        => 'lead.addutmtags',
                    'order'       => $action->getOrder(),
                    'properties'  => [],
                    'formId'      => $form->getId(),
                ],
            ])
        );
        $this->assertResponseIsSuccessful();

        $content     = $this->client->getResponse()->getContent();
        $content     = json_decode($content)->newContent;
        $crawler     = new Crawler($content, $this->client->getInternalRequest()->getUri());
        $formCrawler = $crawler->filter('form');
        $this->assertCount(1, $formCrawler);
        $form = $formCrawler->form();
        $this->client->submit($form);
        $this->assertResponseIsSuccessful();

        $content    = $this->client->getResponse()->getContent();
        $actionHtml = json_decode($content, true)['actionHtml'] ?? null;
        $this->assertNotNull($actionHtml, $content);
        $crawler  = new Crawler($actionHtml);
        $editPage = $crawler->filter('.btn-edit')->attr('href');

        // Check the content was not changed
        $this->client->xmlHttpRequest(Request::METHOD_GET, $editPage);
        $this->assertResponseIsSuccessful();
    }

    /**
     * @param array{
     *      type: string,
     *      properties: array<string, mixed>,
     *      entities?: array<object>
     *  } $inputValues The input configuration for the form action
     * @param array<int, array{
     *      message: string,
     *      message_arg: array<string, mixed>
     *  }> $expectedMessages The expected messages with translation arguments
     */
    #[\PHPUnit\Framework\Attributes\DataProvider('dataTestLabelsForFormActions')]
    public function testLabelsForFormAction(array $inputValues, array $expectedMessages): void
    {
        $form = $this->createForm('test', 'test');

        // Persist entities if provided
        if (!empty($inputValues['entities'])) {
            foreach ($inputValues['entities'] as $entity) {
                $this->em->persist($entity);
            }
        }

        // create form action
        $action = $this->createFormAction($form, $inputValues['type'], $inputValues['properties']);
        $form->addAction(0, $action);
        $this->em->persist($form);

        $this->em->flush();
        $this->em->clear();

        $crawler = $this->client->request('GET', sprintf('/s/forms/edit/%d', $form->getId()));
        $this->assertResponseIsSuccessful();

        $translator = $this->getContainer()->get('translator');
        \assert($translator instanceof TranslatorInterface);

        foreach ($expectedMessages as $expectedMessage) {
            $translatedMessage = $translator->trans($expectedMessage['message'], $expectedMessage['message_arg']);
            $this->assertStringContainsString($translatedMessage, $crawler->html());
        }
    }

    /**
     * @return iterable<string, array{
     *      0: array{
     *          type: string,
     *          properties: array<string, mixed>,
     *          entities?: array<object>
     *      },
     *      1: array<array{
     *          message: string,
     *          message_arg: array<string, mixed>
     *      }>
     *  }>
     */
    public static function dataTestLabelsForFormActions(): iterable
    {
        $category = new Category();
        $category->setTitle('Category');
        $category->setAlias('category');
        $category->setBundle('global');

        $asset = new Asset();
        $asset->setTitle('test');
        $asset->setAlias('test');
        $asset->setCategory($category);

        yield 'Action: Download asset using category' => [
            // input
            [
                'type'       => 'asset.download',
                'properties' => [
                    'asset'    => null,
                    'category' => 1,
                ],
                'entities' => [
                    $category,
                    $asset,
                ],
            ],
            // expected
            [
                [
                    'message'     => 'mautic.form.field.asset.use_category',
                    'message_arg' => [
                        '%category_name%' => $category->getTitle(),
                    ],
                ],
            ],
        ];

        yield 'Action: Add to company points' => [
            // input
            [
                'type'       => 'lead.scorecontactscompanies',
                'properties' => ['score' => 10],
            ],
            // expected
            [
                [
                    'message'     => 'mautic.form.form.change_points_by',
                    'message_arg' => ['%value%' => 10],
                ],
            ],
        ];

        yield 'Action: Add to contact points' => [
            // input
            [
                'type'       => 'lead.pointschange',
                'properties' => [
                    'operator' => 'plus',
                    'points'   => 10,
                    'group'    => 0,
                ],
            ],
            // expected
            [
                [
                    'message'     => 'mautic.form.field.points.operation',
                    'message_arg' => [
                        '%operator%' => '(+)',
                        '%points%'   => 10,
                        '%group%'    => '',
                    ],
                ],
            ],
        ];

        yield 'Action: Email to send to user' => [
            // input
            [
                'type'       => 'email.send.user',
                'properties' => [
                    'useremail' => ['email' => 1],
                    'user_id'   => [1],
                ],
                'entities' => [
                    (new Email())->setName('Email')
                        ->setSubject('Test Subject')
                        ->setIsPublished(true),
                ],
            ],
            // expected
            [
                [
                    'message'     => 'Email',
                    'message_arg' => [],
                ],
                [
                    'message'     => 'Email',
                    'message_arg' => [],
                ],
            ],
        ];

        $segmentOne = new LeadList();
        $segmentOne->setName('list one');
        $segmentOne->setAlias('list_one');
        $segmentOne->setPublicName('list_one');
        $segmentOne->setFilters([]);

        $segmentTwo = new LeadList();
        $segmentTwo->setName('list two');
        $segmentTwo->setAlias('list_two');
        $segmentTwo->setPublicName('list_two');
        $segmentTwo->setFilters([]);

        yield 'Action: Change segments' => [
            // input
            [
                'type'       => 'lead.changelist',
                'properties' => [
                    'addToLists'      => [1],
                    'removeFromLists' => [2],
                ],
                'entities' => [
                    $segmentOne,
                    $segmentTwo,
                ],
            ],
            // expected
            [
                [
                    'message'     => $segmentOne->getName(),
                    'message_arg' => [],
                ],
                [
                    'message'     => $segmentTwo->getName(),
                    'message_arg' => [],
                ],
            ],
        ];
    }

    /**
     * @param array<string, int|string|array<mixed>> $properties
     */
    private function createFormAction(Form $form, string $type, array $properties = []): Action
    {
        $action = new Action();

        $action->setName($type);
        $action->setType($type);
        $action->setForm($form);
        $action->setProperties($properties);

        $this->em->persist($action);

        return $action;
    }

    public function testCloneActionWithCondition(): void
    {
        $form = $this->createForm('Conditional Form', 'Conditional Form');
        $this->em->flush();

        $field1 = $this->createFormField([
            'label'        => 'Country',
            'type'         => 'country',
            'mappedObject' => 'contact',
            'mappedField'  => 'country',
        ])->setForm($form);
        $this->em->persist($field1);

        $field2 = $this->createFormField([
            'label'        => 'State',
            'mappedObject' => 'contact',
            'mappedField'  => 'state',
            'conditions'   => [
                'any'    => 0,
                'expr'   => 'in',
                'values' => ['United States'],
            ],
            'parent' => $field1->getId(),
        ])->setForm($form);

        $fieldSubmit = $this->createFormField([
            'label'        => 'Submit',
            'type'         => 'button',
        ])->setForm($form);

        $this->em->persist($field2);
        $this->em->flush();

        $form->addField($field1->getId(), $field1);
        $form->addField($field2->getId(), $field2);
        $form->addField($fieldSubmit->getId(), $fieldSubmit);

        $field2->setParent((string) $field1->getId());

        $this->em->persist($form);
        $this->em->flush();

        // request for form clone
        $crawler        = $this->client->request(Request::METHOD_GET, "/s/forms/clone/{$form->getId()}");
        $mauticform     = $crawler->filterXPath('//form[@name="mauticform"]')->form();
        $mauticform['mauticform[name]']->setValue('Clone Conditional Form');
        $mauticform['mauticform[isPublished]']->setValue('1');

        $this->client->submit($mauticform);

        $this->assertTrue($this->client->getResponse()->isOk());

        $forms = $this->em->getRepository(Form::class)->findBy([], ['id' => 'ASC']);
        Assert::assertCount(2, $forms);

        $originalForm = $forms[0];
        $clonedForm   = $forms[1];
        Assert::assertSame($form->getId(), $originalForm->getId());
        Assert::assertNotSame($form->getId(), $clonedForm->getId());

        $fields = $clonedForm->getFields()->getValues();
        Assert::assertCount(3, $fields);

        list($clonedField1, $clonedField2, $clonedSubmit) = $fields;
        Assert::assertSame((int) $clonedField2->getParent(), $clonedField1->getId());
    }

    public function testFormWithProject(): void
    {
        $form = $this->createForm('Name', 'Alias');

        $project = new Project();
        $project->setName('Test Project');
        $this->em->persist($project);

        $this->em->flush();
        $this->em->clear();

        $crawler     = $this->client->request('GET', '/s/forms/edit/'.$form->getId());
        $formCrawler = $crawler->selectButton('Save')->form();
        $formCrawler['mauticform[projects]']->setValue((string) $project->getId());

        $this->client->submit($formCrawler);

        $this->assertResponseIsSuccessful();

        $savedForm = $this->em->find(Form::class, $form->getId());
        Assert::assertSame($project->getId(), $savedForm->getProjects()->first()->getId());
    }

    public function testFormDetailsViewWithPreviewPanel(): void
    {
        // Create a form
        $form = $this->createForm('Test Form Details', 'test_form_details');
        $this->em->persist($form);
        $this->em->flush();

        // Request the form details view
        $crawler = $this->client->request('GET', sprintf('/s/forms/view/%d', $form->getId()));
        $this->assertResponseIsSuccessful();

        // Check if preview panel exists
        $previewPanel = $crawler->filter('div.panel.shd-none.bdr-rds-0.bdr-w-0.mt-sm.mb-0');

        if ($previewPanel->count() > 0) {
            // If preview panel exists, verify its structure
            $panelHeading = $previewPanel->filter('.panel-heading .panel-title:contains("Preview")');
            $this->assertCount(1, $panelHeading, 'Preview panel should have correct heading structure');

            $panelBody = $previewPanel->filter('.panel-body.pt-xs');
            $this->assertCount(1, $panelBody, 'Preview panel should have correct body structure');
        }
    }

    public function testSliderFieldRendersWithInputAttributes(): void
    {
        // Create a form with a slider field
        $form = $this->createForm('Test Slider Form', 'test_slider_form');
        $this->em->persist($form);
        $this->em->flush();

        // Create a slider field
        $sliderField = $this->createFormField([
            'label' => 'Test Slider',
            'type'  => 'slider',
        ]);
        $sliderField->setProperties([
            'min'  => 0,
            'max'  => 100,
            'step' => 5,
        ]);
        $sliderField->setForm($form);
        $sliderField->setOrder(1);
        $this->em->persist($sliderField);

        $this->em->flush();
        $this->em->clear();

        // Request the form preview instead of view
        $crawler = $this->client->request('GET', sprintf('/s/forms/preview/%d', $form->getId()));
        $this->assertResponseIsSuccessful();

        // Check that the slider input has the oninput attribute
        $sliderInput = $crawler->filter('input[type="range"]');
        $this->assertCount(1, $sliderInput, 'Slider input should be present');

        $oninputAttr = $sliderInput->attr('oninput');
        $this->assertNotNull($oninputAttr, 'Slider input should have oninput attribute');
        $this->assertStringContainsString('document.getElementById', $oninputAttr, 'Slider input should use getElementById to target output element');
        $this->assertStringContainsString('.textContent = this.value', $oninputAttr, 'Slider input should set output value to input value');
    }

    private function createForm(string $name, string $alias): Form
    {
        $form = new Form();
        $form->setName($name);
        $form->setAlias($alias);
        $form->setPostActionProperty('Success');
        $this->em->persist($form);

        return $form;
    }

    /**
     * @param array<string,mixed> $data
     */
    private function createFormField(array $data = []): Field
    {
        $field     = new Field();
        $aliasSlug = strtolower(str_replace(' ', '_', $data['label'] ?? 'Field 1'));
        $field->setLabel($data['label'] ?? 'Field 1');
        $field->setAlias('field_'.$aliasSlug);
        $field->setType($data['type'] ?? 'text');
        $field->setMappedObject($data['mappedObject'] ?? '');
        $field->setMappedField($data['mappedField'] ?? '');
        $field->setConditions($data['conditions'] ?? []);
        $this->em->persist($field);

        return $field;
    }
}
