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

use Chill\BudgetBundle\Entity\AbstractElement;
use Chill\BudgetBundle\Security\Authorization\BudgetElementVoter;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;

abstract class AbstractElementController extends AbstractController
{
    public function __construct(
        protected EntityManagerInterface $em,
        protected TranslatorInterface $translator,
        protected LoggerInterface $chillMainLogger,
        protected ManagerRegistry $managerRegistry,
    ) {}

    /**
     * Route(
     *  "{_locale}/family-members/family-members/{id}/delete",
     *  name="chill_family_members_family_members_delete"
     * ).
     */
    protected function _delete(AbstractElement $element, Request $request, mixed $template, mixed $flashMessage): Response
    {
        $this->denyAccessUnlessGranted(BudgetElementVoter::DELETE, $element, 'You are not '
            .'allowed to delete this item');

        $form = $this->createDeleteForm();

        if (null !== $element->getPerson()) {
            $entity = $element->getPerson();
            $indexPage = 'chill_budget_elements_index';
        } else {
            $entity = $element->getHousehold();
            $indexPage = 'chill_budget_elements_household_index';
        }

        if (Request::METHOD_POST === $request->getMethod()) {
            $form->handleRequest($request);

            if ($form->isSubmitted() && $form->isValid()) {
                $this->chillMainLogger->notice('A budget element has been removed', [
                    'family_element' => $element::class,
                    'by_user' => $this->getUser()->getUsername(),
                    'family_member_id' => $element->getId(),
                    'amount' => $element->getAmount(),
                    'type' => $element->getType(),
                ]);

                $em = $this->managerRegistry->getManager();
                $em->remove($element);
                $em->flush();

                $this->addFlash('success', $this->translator
                    ->trans($flashMessage));

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

        return $this->render($template, [
            'element' => $element,
            'delete_form' => $form->createView(),
        ]);
    }

    /**
     * @param string $template
     * @param string $flashOnSuccess
     */
    protected function _edit(AbstractElement $element, Request $request, $template, $flashOnSuccess): Response
    {
        $this->denyAccessUnlessGranted(BudgetElementVoter::UPDATE, $element);

        if (null !== $element->getPerson()) {
            $entity = $element->getPerson();
            $entityStr = 'person';
            $indexPage = 'chill_budget_elements_index';
        } else {
            $entity = $element->getHousehold();
            $entityStr = 'household';
            $indexPage = 'chill_budget_elements_household_index';
        }

        $entity = $element->getPerson() ?? $element->getHousehold();

        $form = $this->createForm($this->getType(), $element);
        $form->add('submit', SubmitType::class);

        $form->handleRequest($request);

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

            $this->addFlash('success', $this->translator->trans($flashOnSuccess));

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

        return $this->render($template, [
            'element' => $element,
            'form' => $form->createView(),
            $entityStr => $entity,
        ]);
    }

    protected function _new(mixed $entity, Request $request, mixed $template, mixed $flashMessageOnSuccess)
    {
        /** @var AbstractElement $element */
        $element = $this->createNewElement();

        if ($entity instanceof Person) {
            $element->setPerson($entity);
            $entityStr = 'person';
            $indexPage = 'chill_budget_elements_index';
        } else {
            $element->setHousehold($entity);
            $entityStr = 'household';
            $indexPage = 'chill_budget_elements_household_index';
        }

        // $this->denyAccessUnlessGranted(BudgetElementVoter::CREATE, $entity);

        $form = $this->createForm($this->getType(), $element);
        $form->add('submit', SubmitType::class);

        $form->handleRequest($request);

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

            $this->addFlash('success', $this->translator->trans($flashMessageOnSuccess));

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

        if ($form->isSubmitted()) {
            $this->addFlash('error', $this->translator->trans('This form contains errors'));
        }

        return $this->render($template, [
            'form' => $form->createView(),
            $entityStr => $entity,
            'element' => $element,
        ]);
    }

    /**
     * Route(
     *  "{_locale}/family-members/family-members/{id}/view",
     *  name="chill_family_members_family_members_view"
     * ).
     */
    protected function _view(AbstractElement $element, mixed $template)
    {
        $this->denyAccessUnlessGranted(BudgetElementVoter::SEE, $element);

        return $this->render($template, [
            'element' => $element,
        ]);
    }

    /**
     * @return AbstractElement the newly created element
     */
    abstract protected function createNewElement();

    abstract protected function getType();

    /**
     * Creates a form to delete a help request entity by id.
     */
    private function createDeleteForm(): \Symfony\Component\Form\FormInterface
    {
        return $this->createFormBuilder()
            ->add('submit', SubmitType::class, ['label' => 'Delete'])
            ->getForm();
    }
}
