<?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\PersonBundle\CRUD\Controller;

use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\QueryBuilder;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Class EntityPersonCRUDController
 * CRUD Controller for entities attached to a Person.
 */
class EntityPersonCRUDController extends CRUDController
{
    public function __construct(protected readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry) {}

    protected function generateTemplateParameter(string $action, mixed $entity, Request $request, array $defaultTemplateParameters = [])
    {
        $templateParameters = parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters);

        $templateParameters['person'] = $this->getPerson($request);

        return $templateParameters;
    }

    /**
     * Override the base method to add a filtering step to a person.
     *
     * @return QueryBuilder
     */
    protected function buildQueryEntities(string $action, Request $request)
    {
        $qb = parent::buildQueryEntities($action, $request);

        return $this->filterQueryEntitiesByPerson($action, $qb, $request);
    }

    /**
     * @param \Chill\MainBundle\CRUD\Controller\string|string $action
     */
    protected function createEntity($action, Request $request): object
    {
        $entity = parent::createEntity($action, $request);

        $person = $this->getPerson($request);

        $entity->setPerson($person);

        return $entity;
    }

    /**
     * Add a where clause to the buildQuery.
     *
     * @param \Chill\PersonBundle\CRUD\Controller\QueryBuilder $qb
     *
     * @return \Chill\PersonBundle\CRUD\Controller\QueryBuilder
     */
    protected function filterQueryEntitiesByPerson(string $action, QueryBuilder $qb, Request $request): QueryBuilder
    {
        $qb->andWhere($qb->expr()->eq('e.person', ':person'));
        $qb->setParameter('person', $this->getPerson($request));

        return $qb;
    }

    /**
     * Extract the person from the request.
     *
     * the person parameter will be `person_id` and must be
     * present in the query
     *
     * If the parameter is not set, this method will return null.
     *
     * If the person id does not exists, the method will throw a
     * Symfony\Component\HttpKernel\Exception\NotFoundHttpException
     *
     * @throws Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the person with given id is not found
     */
    protected function getPerson(Request $request): ?Person
    {
        if (false === $request->query->has('person_id')) {
            return null;
        }

        $person = $this->managerRegistry
            ->getRepository(Person::class)
            ->find($request->query->getInt('person_id'));

        if (null === $person) {
            throw $this->createNotFoundException('the person with this id is not found');
        }

        return $person;
    }

    /**
     * @param string $action
     *
     * @return string
     */
    protected function getTemplateFor($action, $entity, Request $request)
    {
        if ($this->hasCustomTemplate($action, $entity, $request)) {
            return $this->getActionConfig($action)['template'];
        }

        return match ($action) {
            'new' => '@ChillPerson/CRUD/new.html.twig',
            'edit' => '@ChillPerson/CRUD/edit.html.twig',
            'view' => '@ChillPerson/CRUD/view.html.twig',
            'delete' => '@ChillPerson/CRUD/delete.html.twig',
            'index' => '@ChillPerson/CRUD/index.html.twig',
            default => parent::getTemplateFor($action, $entity, $request),
        };
    }

    protected function onBeforeRedirectAfterSubmission(string $action, $entity, \Symfony\Component\Form\FormInterface $form, Request $request): ?Response
    {
        $next = $request->request->get('submit', 'save-and-close');

        return match ($next) {
            'save-and-close' => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_index', [
                'person_id' => $this->getPerson($request)->getId(),
            ]),
            'save-and-new' => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_new', [
                'person_id' => $this->getPerson($request)->getId(),
            ]),
            'new' => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [
                'id' => $entity->getId(),
                'person_id' => $this->getPerson($request)->getId(),
            ]),
            default => $this->redirectToRoute('chill_crud_'.$this->getCrudName().'_view', [
                'id' => $entity->getId(),
                'person_id' => $this->getPerson($request)->getId(),
            ]),
        };
    }
}
