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

use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Form\AccompanyingCourseCommentType;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodCommentVoter;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;

class AccompanyingCourseCommentController extends AbstractController
{
    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly FormFactoryInterface $formFactory,
        private readonly TranslatorInterface $translator,
        private readonly ManagerRegistry $managerRegistry,
    ) {}

    /**
     * Page of comments in Accompanying Course section.
     *
     * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"})
     */
    #[Route(path: '/{_locale}/parcours/{accompanying_period_id}/comments', name: 'chill_person_accompanying_period_comment_list')]
    public function commentAction(AccompanyingPeriod $accompanyingCourse, Request $request): Response
    {
        $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE_DETAILS, $accompanyingCourse);

        $em = $this->managerRegistry->getManager();
        $afterSuccessfulRedirectResponse = $this->redirectToRoute('chill_person_accompanying_period_comment_list', [
            'accompanying_period_id' => $accompanyingCourse->getId(),
        ]);

        if ($request->query->has('edit') && $this->isGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse)) {
            foreach ($accompanyingCourse->getComments() as $comment) {
                if ($comment->getId() === $request->query->getInt('edit')) {
                    $editForm = $this->createCommentForm($comment, 'edit');
                    $commentEditId = $comment->getId();
                    $commentEdited = $comment;
                }
            }
            $pinnedComment = $accompanyingCourse->getPinnedComment();

            if (null !== $pinnedComment && $pinnedComment->getId() === $request->query->getInt('edit')) {
                $editForm = $this->createCommentForm($pinnedComment, 'edit');
                $commentEditId = $pinnedComment->getId();
                $commentEdited = $pinnedComment;
            }

            if (!isset($editForm)) {
                throw new NotFoundHttpException('comment with id '.$request->query->getInt('edit').' is not found');
            }

            if (isset($commentEdited)) {
                $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::EDIT, $commentEdited);
            } else {
                throw new \LogicException('at this step, commentEdited should be set');
            }

            $editForm->handleRequest($request);

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

                return $afterSuccessfulRedirectResponse;
            }

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

        if ($this->isGranted(AccompanyingPeriodVoter::EDIT, $accompanyingCourse)) {
            $newComment = new AccompanyingPeriod\Comment();
            $newComment->setAccompanyingPeriod($accompanyingCourse);

            $newForm = $this->createCommentForm($newComment, 'new');
            $newForm->handleRequest($request);

            if ($newForm->isSubmitted() && $newForm->isValid()) {
                $em->persist($newComment);
                $em->flush();

                return $afterSuccessfulRedirectResponse;
            }
        }

        return $this->render('@ChillPerson/AccompanyingCourse/Comment/index.html.twig', [
            'accompanyingCourse' => $accompanyingCourse,
            'form' => isset($newForm) ? $newForm->createView() : null,
            'edit_form' => isset($editForm) ? $editForm->createView() : null,
            'commentEditId' => $commentEditId ?? null,
        ]);
    }

    /**
     * Delete an existing comment.
     */
    #[Route(path: '/{_locale}/parcours/comment/{id}/delete', name: 'chill_person_accompanying_period_comment_delete')]
    public function deleteAction(AccompanyingPeriod\Comment $comment, Request $request): Response
    {
        $this->denyAccessUnlessGranted(AccompanyingPeriodCommentVoter::DELETE, $comment);

        $form = $this->createForm(FormType::class, []);
        $form->add('submit', SubmitType::class, ['label' => 'Confirm']);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $this->entityManager->remove($comment);

            if ($comment->getAccompanyingPeriod()->getPinnedComment() === $comment) {
                $comment->getAccompanyingPeriod()->setPinnedComment(null);
            }

            $this->entityManager->flush();

            $this->addFlash('success', $this->translator->trans('accompanying_course_comment.Comment removed'));

            return $this->redirect(
                $request->query->has('returnPath') ? $request->query->get('returnPath') :
                        $this->generateUrl('chill_person_accompanying_period_comment_list', [
                            'accompanying_period_id' => $comment->getAccompanyingPeriod()->getId(),
                        ])
            );
        }

        return $this->render('@ChillPerson/AccompanyingCourse/Comment/confirm_delete.html.twig', [
            'comment' => $comment,
            'delete_form' => $form->createView(),
            'accompanyingCourse' => $comment->getAccompanyingPeriod(),
        ]);
    }

    #[Route(path: '/{_locale}/parcours/comment/{id}/pin', name: 'chill_person_accompanying_period_comment_pin')]
    public function pinComment(AccompanyingPeriod\Comment $comment): Response
    {
        $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $comment->getAccompanyingPeriod());

        $comment->getAccompanyingPeriod()->setPinnedComment($comment);

        $this->managerRegistry->getManager()->flush();

        $this->addFlash('success', $this->translator->trans('accompanying_course.comment is pinned'));

        return $this->redirectToRoute('chill_person_accompanying_period_comment_list', [
            'accompanying_period_id' => $comment->getAccompanyingPeriod()->getId(),
        ]);
    }

    #[Route(path: '/{_locale}/parcours/comment/{id}/unpin', name: 'chill_person_accompanying_period_comment_unpin')]
    public function unpinComment(AccompanyingPeriod\Comment $comment): Response
    {
        $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $comment->getAccompanyingPeriod());

        $comment->getAccompanyingPeriod()->setPinnedComment(null);

        $this->managerRegistry->getManager()->flush();

        $this->addFlash('success', $this->translator->trans('accompanying_course.comment is unpinned'));

        return $this->redirectToRoute('chill_person_accompanying_period_comment_list', [
            'accompanying_period_id' => $comment->getAccompanyingPeriod()->getId(),
        ]);
    }

    private function createCommentForm(AccompanyingPeriod\Comment $comment, string $step): FormInterface
    {
        return $this->formFactory->createNamed($step, AccompanyingCourseCommentType::class, $comment);
    }
}
