<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\CustomFieldsBundle\Controller;

use Chill\CustomFieldsBundle\Entity\CustomField;
use Chill\CustomFieldsBundle\Entity\CustomFieldsDefaultGroup;
use Chill\CustomFieldsBundle\Entity\CustomFieldsGroup;
use Chill\CustomFieldsBundle\Form\CustomFieldsGroupType;
use Chill\CustomFieldsBundle\Form\DataTransformer\CustomFieldsGroupToIdTransformer;
use Chill\CustomFieldsBundle\Form\Type\CustomFieldType as FormTypeCustomField;
use Chill\CustomFieldsBundle\Service\CustomFieldProvider;
use Doctrine\ORM\Query;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;

/**
 * Class CustomFieldsGroupController.
 */
class CustomFieldsGroupController extends AbstractController
{
    /**
     * CustomFieldsGroupController constructor.
     */
    public function __construct(
        private readonly CustomFieldProvider $customFieldProvider,
        private readonly TranslatorInterface $translator,
        private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
    ) {}

    /**
     * Creates a new CustomFieldsGroup entity.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/create', name: 'customfieldsgroup_create')]
    public function createAction(Request $request)
    {
        $entity = new CustomFieldsGroup();
        $form = $this->createCreateForm($entity);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $em = $this->managerRegistry->getManager();
            $em->persist($entity);
            $em->flush();

            $this->addFlash('success', $this->translator
                ->trans('The custom fields group has been created'));

            return $this->redirectToRoute('customfieldsgroup_show', ['id' => $entity->getId()]);
        }

        $this->addFlash('error', $this->translator
            ->trans('The custom fields group form contains errors'));

        return $this->render('@ChillCustomFields/CustomFieldsGroup/new.html.twig', [
            'entity' => $entity,
            'form' => $form->createView(),
        ]);
    }

    /**
     * Displays a form to edit an existing CustomFieldsGroup entity.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/{id}/edit', name: 'customfieldsgroup_edit')]
    public function editAction(mixed $id)
    {
        $em = $this->managerRegistry->getManager();

        $entity = $em->getRepository(CustomFieldsGroup::class)->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.');
        }

        $editForm = $this->createEditForm($entity);

        return $this->render('@ChillCustomFields/CustomFieldsGroup/edit.html.twig', [
            'entity' => $entity,
            'edit_form' => $editForm->createView(),
        ]);
    }

    /**
     * Lists all CustomFieldsGroup entities.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/', name: 'customfieldsgroup')]
    public function indexAction()
    {
        $em = $this->managerRegistry->getManager();

        $cfGroups = $em->getRepository(CustomFieldsGroup::class)->findAll();
        $defaultGroups = $this->getDefaultGroupsId();

        $makeDefaultFormViews = [];

        foreach ($cfGroups as $group) {
            if (!\in_array($group->getId(), $defaultGroups, true)) {
                $makeDefaultFormViews[$group->getId()] = $this->createMakeDefaultForm($group)->createView();
            }
        }

        return $this->render('@ChillCustomFields/CustomFieldsGroup/index.html.twig', [
            'entities' => $cfGroups,
            'default_groups' => $defaultGroups,
            'make_default_forms' => $makeDefaultFormViews,
        ]);
    }

    /**
     * Set the CustomField Group with id $cFGroupId as default.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/makedefault', name: 'customfieldsgroup_makedefault')]
    public function makeDefaultAction(Request $request)
    {
        $form = $this->createMakeDefaultForm(null);
        $form->handleRequest($request);

        $cFGroupId = $form->get('id')->getData();

        $em = $this->managerRegistry->getManager();

        $cFGroup = $em->getRepository(CustomFieldsGroup::class)->findOneById($cFGroupId);

        if (!$cFGroup) {
            throw $this->createNotFoundException('customFieldsGroup not found with '."id {$cFGroupId}");
        }

        $cFDefaultGroup = $em->getRepository(CustomFieldsDefaultGroup::class)
            ->findOneByEntity($cFGroup->getEntity());

        if ($cFDefaultGroup) {
            $em->remove($cFDefaultGroup);
            $em->flush(); /*this is necessary, if not doctrine
             * will not remove old entity before adding a new one,
             * and this leads to violation constraint of unique entity
             * in postgresql
             */
        }

        $newCFDefaultGroup = new CustomFieldsDefaultGroup();
        $newCFDefaultGroup->setCustomFieldsGroup($cFGroup);
        $newCFDefaultGroup->setEntity($cFGroup->getEntity());

        $em->persist($newCFDefaultGroup);
        $em->flush();

        $this->addFlash('success', $this->translator
            ->trans('The default custom fields group has been changed'));

        return $this->redirectToRoute('customfieldsgroup');
    }

    /**
     * Displays a form to create a new CustomFieldsGroup entity.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/new', name: 'customfieldsgroup_new')]
    public function newAction()
    {
        $entity = new CustomFieldsGroup();
        $form = $this->createCreateForm($entity);

        return $this->render('@ChillCustomFields/CustomFieldsGroup/new.html.twig', [
            'entity' => $entity,
            'form' => $form->createView(),
        ]);
    }

    /**
     * This function render the customFieldsGroup as a form.
     *
     * This function is for testing purpose !
     *
     * The route which call this action is not in Resources/config/routing.yml,
     * but in Tests/Fixtures/App/app/config.yml
     *
     * @param int $id
     */
    public function renderFormAction($id, Request $request)
    {
        $em = $this->managerRegistry->getManager();

        $entity = $em->getRepository(CustomFieldsGroup::class)->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find CustomFieldsGroups entity.');
        }

        $form = $this->createForm(FormTypeCustomField::class, null, ['group' => $entity]);
        $form->add('submit_dump', SubmitType::class, ['label' => 'POST AND DUMP']);
        $form->add('submit_render', SubmitType::class, ['label' => 'POST AND RENDER']);
        $form->handleRequest($request);

        $this->get('twig.loader')
            ->addPath(
                __DIR__.'/../Tests/Fixtures/App/app/Resources/views/',
                $namespace = 'test'
            );

        if ($form->isSubmitted()) {
            if ($form->get('submit_render')->isClicked()) {
                return $this->render('@ChillCustomFields/CustomFieldsGroup/render_for_test.html.twig', [
                    'fields' => $form->getData(),
                    'customFieldsGroup' => $entity,
                ]);
            }

            // dump($form->getData());
            // dump(json_enccode($form->getData()));
        }

        return $this
            ->render('@test/CustomField/simple_form_render.html.twig', [
                'form' => $form->createView(),
            ]);
    }

    /**
     * Finds and displays a CustomFieldsGroup entity.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/{id}/show', name: 'customfieldsgroup_show')]
    public function showAction(mixed $id)
    {
        $em = $this->managerRegistry->getManager();

        $entity = $em->getRepository(CustomFieldsGroup::class)->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.');
        }

        $options = $this->getOptionsAvailable($entity->getEntity());

        return $this->render('@ChillCustomFields/CustomFieldsGroup/show.html.twig', [
            'entity' => $entity,
            'create_field_form' => $this->createCreateFieldForm($entity)->createView(),
            'options' => $options,
        ]);
    }

    /**
     * Edits an existing CustomFieldsGroup entity.
     */
    #[Route(path: '/{_locale}/admin/customfieldsgroup/{id}/update', name: 'customfieldsgroup_update')]
    public function updateAction(Request $request, mixed $id)
    {
        $em = $this->managerRegistry->getManager();

        $entity = $em->getRepository(CustomFieldsGroup::class)->find($id);

        if (!$entity) {
            throw $this->createNotFoundException('Unable to find CustomFieldsGroup entity.');
        }

        $editForm = $this->createEditForm($entity);
        $editForm->handleRequest($request);

        if ($editForm->isSubmitted() && $editForm->isValid()) {
            $em->flush();

            $this->addFlash('success', $this->translator
                ->trans('The custom fields group has been updated'));

            return $this->redirectToRoute('customfieldsgroup_edit', ['id' => $id]);
        }

        $this->addFlash('error', $this->translator
            ->trans('The custom fields group form contains errors'));

        return $this->render('@ChillCustomFields/CustomFieldsGroup/edit.html.twig', [
            'entity' => $entity,
            'edit_form' => $editForm->createView(),
        ]);
    }

    private function createCreateFieldForm(CustomFieldsGroup $customFieldsGroup)
    {
        $fieldChoices = [];

        foreach ($this->customFieldProvider->getAllFields() as $key => $customType) {
            $fieldChoices[$key] = $customType->getName();
        }

        $customfield = (new CustomField())
            ->setCustomFieldsGroup($customFieldsGroup);

        $builder = $this->get('form.factory')
            ->createNamedBuilder('', FormType::class, $customfield, [
                'method' => 'GET',
                'action' => $this->generateUrl('customfield_new'),
                'csrf_protection' => false,
            ])
            ->add('type', ChoiceType::class, [
                'choices' => array_combine(array_values($fieldChoices), array_keys($fieldChoices)),
            ])
            ->add('customFieldsGroup', HiddenType::class)
            ->add('submit', SubmitType::class);
        $builder->get('customFieldsGroup')
            ->addViewTransformer(new CustomFieldsGroupToIdTransformer(
                $this->managerRegistry->getManager()
            ));

        return $builder->getForm();
    }

    /**
     * Creates a form to create a CustomFieldsGroup entity.
     *
     * @param CustomFieldsGroup $entity The entity
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createCreateForm(CustomFieldsGroup $entity)
    {
        $form = $this->createForm(CustomFieldsGroupType::class, $entity, [
            'action' => $this->generateUrl('customfieldsgroup_create'),
            'method' => 'POST',
        ]);

        $form->add('submit', SubmitType::class, ['label' => 'Create']);

        return $form;
    }

    /**
     * Creates a form to edit a CustomFieldsGroup entity.
     *
     * @param CustomFieldsGroup $entity The entity
     *
     * @return \Symfony\Component\Form\Form The form
     */
    private function createEditForm(CustomFieldsGroup $entity)
    {
        $form = $this->createForm(CustomFieldsGroupType::class, $entity, [
            'action' => $this->generateUrl('customfieldsgroup_update', ['id' => $entity->getId()]),
            'method' => 'PUT',
        ]);
        $form->add('submit', SubmitType::class, ['label' => 'Update']);

        return $form;
    }

    /**
     * create a form to make the group default.
     *
     * @return \Symfony\Component\Form\Form
     */
    private function createMakeDefaultForm(?CustomFieldsGroup $group = null)
    {
        return $this->createFormBuilder($group, [
            'method' => 'POST',
            'action' => $this->generateUrl('customfieldsgroup_makedefault'),
        ])
            ->add('id', HiddenType::class)
            ->add('submit', SubmitType::class, ['label' => 'Make default'])
            ->getForm();
    }

    /**
     * Get an array of CustomFieldsGroupId which are marked as default
     * for their entity.
     *
     * @return int[]
     */
    private function getDefaultGroupsId()
    {
        $em = $this->managerRegistry->getManager();

        $customFieldsGroupIds = $em->createQuery('SELECT g.id FROM '
                .CustomFieldsDefaultGroup::class.' d '
                .'JOIN d.customFieldsGroup g')
            ->getResult(Query::HYDRATE_SCALAR);

        $result = [];

        foreach ($customFieldsGroupIds as $row) {
            $result[] = $row['id'];
        }

        return $result;
    }

    /**
     * Return an array of available key option for custom fields group
     * on the given entity.
     *
     * @param string $entity the entity to filter
     */
    private function getOptionsAvailable($entity)
    {
        $options = $this->getParameter('chill_custom_fields.'
              .'customizables_entities');

        foreach ($options as $key => $definition) {
            if ($definition['class'] === $entity) {
                foreach ($definition['options'] as $key => $value) {
                    yield $key;
                }
            }
        }
        //    [$entity->getEntity()];
    }
}
