<?php

namespace App\Controller;

use App\Entity\Capsule;
use App\Entity\PendingEditorInvitation;
use App\Entity\User;
use App\Form\CapsuleEditorsFormType;
use App\Form\RemoveEditorFormType;
use App\Repository\CapsuleRepository;
use App\Repository\PendingEditorInvitationRepository;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

class CapsuleEditorController extends AbstractController
{
    public function __construct(
        private MailerInterface $mailer,
        private TranslatorInterface $translator,
        private PendingEditorInvitationRepository $capsule_pending_editor_invitation_repository,
        private EntityManagerInterface $entity_manager,
        private UrlGeneratorInterface $urlGenerator,
        private CapsuleRepository $capsule_repository,
        private UserRepository $user_repository
    ) {
    }

    #[Route('/{_locale<%app.supported_locales%>}/capsule/{capsule_id}/editors', name:'edit_capsule_editors')]
    public function editCapsuleEditors(
        Request $request,
        int $capsule_id
    ): Response {
        $current_user = $this->getUser();
        if (! $current_user instanceof User) {
            return $this->redirectToRoute('app_logout');
        }

        $capsule = $this->capsule_repository->find($capsule_id);
        if (! $capsule) {
            throw $this->createNotFoundException(
                'No capsule found for id ' . $capsule_id
            );
        }

        $current_capsule_editors_users = $capsule->getEditors()->toArray();
        if (! $capsule->getEditors()->contains($current_user)) {
            $this->addFlash(
                'warning',
                $this->translator->trans(
                    'editors.user_not_editor_error',
                    [
                        'capsule_name' => $capsule->getName()
                    ]
                )
            );

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

        $form = $this->createForm(CapsuleEditorsFormType::class);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $editor_email = $form->get('email')->getData();
            $user_associated_with_email_address = $this->user_repository
                                                ->findOneBy(['email' => $editor_email]);

            if (! $user_associated_with_email_address instanceof User) {
                $this->addPendingEditor($editor_email, $capsule, $current_user);
            } else {
                $this->addEditor(
                    $editor_email,
                    $capsule,
                    $current_user,
                    $user_associated_with_email_address,
                    $current_capsule_editors_users
                );
            }

            return $this->redirectToRoute('edit_capsule_editors', [
                'capsule_id' => $capsule_id
            ]);
        }

        $pending_editors = $this->capsule_pending_editor_invitation_repository->findBy(['capsule_id' => $capsule_id]);

        return $this->renderForm('capsule/editors/list_editors.html.twig', [
            'userPermissionsCapsuleForm' => $form,
            'capsule' => $capsule,
            'editors' => $current_capsule_editors_users,
            'pending_editors' => $pending_editors,
            'current_user' => $current_user
        ]);
    }

    #[Route(
        '/{_locale<%app.supported_locales%>}/capsule/{capsule_id}/editors/{editor_id}/remove',
        name:'remove_editor'
    )]
    public function removeEditor(
        int $capsule_id,
        int $editor_id,
        Request $request
    ): Response {
        $form = $this->createForm(RemoveEditorFormType::class);
        $form->handleRequest($request);

        $capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]);
        if (! $capsule instanceof Capsule) {
            throw new \Exception('The retrieved capsule is not an instance of Capsule.');
        }

        $editor = $this->user_repository->findOneBy(['id' => $editor_id]);
        if (! $editor instanceof User) {
            throw new \Exception('The retrieved user is not an instance of User.');
        }

        $current_user = $this->getUser();
        if (! $current_user instanceof User) {
            return $this->redirectToRoute('app_logout');
        }

        if ($editor_id === $capsule->getCreationAuthor()->getId()) {
            $this->addFlash(
                'warning',
                $this->translator->trans(
                    'editors.remove.editor.error',
                    [
                        'editor_email' => $editor->getEmail(),
                        'capsule_name' => $capsule->getName()
                    ]
                )
            );

            return $this->redirectToRoute('edit_capsule_editors', [
                'capsule_id' => $capsule->getId()
            ]);
        }

        if ($form->isSubmitted() && $form->isValid()) {
            $capsule->removeEditor($editor);
            $this->entity_manager->flush();

            $this->addFlash(
                'success',
                $this->translator->trans(
                    'editors.remove.editor.success',
                    [
                        'editor_email' => $editor->getEmail(),
                        'capsule_name' => $capsule->getName()
                    ]
                )
            );

            return $this->redirectToRoute('edit_capsule_editors', [
                'capsule_id' => $capsule->getId()
            ]);
        }

        return $this->renderForm('capsule/editors/remove_editor.html.twig', [
            'removeEditorForm' => $form,
            'editor_email' => $editor->getEmail(),
            'capsule_id' => $capsule_id
        ]);
    }

    #[Route(
        '/{_locale<%app.supported_locales%>}/capsule/{capsule_id}/pending_editor/{pending_editor_invitation_id}/remove',
        name:'remove_pending_editor'
    )]
    public function removePendingEditor(
        int $pending_editor_invitation_id,
        int $capsule_id,
        Request $request
    ): Response {
        $capsule = $this->capsule_repository->findOneBy(['id' => $capsule_id]);
        if (! $capsule instanceof Capsule) {
            throw new \Exception('The retrieved capsule is not an instance of Capsule.');
        }

        $pending_editor_invitation = $this->capsule_pending_editor_invitation_repository
                                            ->findOneBy(['id' => $pending_editor_invitation_id]);

        $form = $this->createForm(RemoveEditorFormType::class);
        $form->handleRequest($request);

        if (! $pending_editor_invitation instanceof PendingEditorInvitation) {
            $this->addFlash(
                'warning',
                $this->translator->trans(
                    'editors.remove.pending_editor.error',
                    [
                        'capsule_name' => $capsule->getName()
                    ]
                )
            );

            return $this->redirectToRoute('edit_capsule_editors', [
                'capsule_id' => $capsule_id
            ]);
        }

        if ($form->isSubmitted() && $form->isValid()) {
            $this->entity_manager->remove($pending_editor_invitation);
            $this->entity_manager->flush();

            $this->addFlash(
                'success',
                $this->translator->trans(
                    'editors.remove.pending_editor.success',
                    [
                        'pending_editor_email' => $pending_editor_invitation->getEmail(),
                        'capsule_name' => $capsule->getName()
                    ]
                )
            );

            return $this->redirectToRoute('edit_capsule_editors', [
                'capsule_id' => $capsule_id
            ]);
        }

        return $this->renderForm('capsule/editors/remove_pending_editor.html.twig', [
            'removeEditorForm' => $form,
            'editor_email' => $pending_editor_invitation->getEmail(),
            'capsule_id' => $capsule_id
        ]);
    }

    private function addPendingEditor(string $editor_email, Capsule $capsule, User $current_user): void
    {
        $pending_editors_emails = $this->capsule_pending_editor_invitation_repository
            ->getPendingEditorsEmails($capsule->getId());

        if (in_array($editor_email, $pending_editors_emails)) {
            $this->addFlash(
                'warning',
                $this->translator->trans(
                    'editors.add.pending_editor.already_added',
                    [
                        'user_email' => $editor_email
                    ]
                )
            );
            return;
        }

        $pending_editor_invitation = new PendingEditorInvitation();
        $pending_editor_invitation->setCapsuleId($capsule->getId());
        $pending_editor_invitation->setEmail($editor_email);
        $this->entity_manager->persist($pending_editor_invitation);
        $this->entity_manager->flush();

        $email = (new TemplatedEmail())
            ->to($editor_email)
            ->subject($this->translator->trans('editors.add.pending_editor.email.title'))
            ->htmlTemplate('capsule/editors/email_pending_editor.html.twig')
            ->context([
                'user' => $current_user,
                'capsule' => $capsule
            ]);

        $this->mailer->send($email);

        $this->addFlash(
            'success',
            $this->translator->trans(
                'editors.add.pending_editor.success',
                [
                    'user_email' => $editor_email
                ]
            )
        );
    }

    /**
     * @param array<User> $current_capsule_editors_users
     * @throws TransportExceptionInterface
     */
    private function addEditor(
        string $editor_email,
        Capsule $capsule,
        User $current_user,
        User $user_associated_with_email_address,
        array $current_capsule_editors_users
    ): void {
        if (in_array($user_associated_with_email_address, $current_capsule_editors_users)) {
            $this->addFlash(
                'warning',
                $this->translator->trans(
                    'editors.add.user.already_added',
                    [
                        'user_email' => $editor_email
                    ]
                )
            );
            $link = null;
        } else {
            $link = $this->urlGenerator->generate(
                'edit_capsule',
                [ 'path' => $capsule->getLinkPath() ],
                UrlGeneratorInterface::ABSOLUTE_URL
            );

            $capsule->addEditor($user_associated_with_email_address);
            $this->entity_manager->persist($capsule);
            $this->entity_manager->flush();

            $this->addFlash(
                'success',
                $this->translator->trans(
                    'editors.add.user.success',
                    [
                        'capsule_name' => $capsule->getName(),
                        'user_email' => $editor_email
                    ]
                )
            );
        }

        $email = (new TemplatedEmail())
            ->to($editor_email)
            ->subject($this->translator->trans('editors.add.user.email.title'))
            ->htmlTemplate('capsule/editors/email_editor.html.twig')
            ->context([
                'user' => $current_user,
                'capsule' => $capsule,
                'capsule_edit_link' => $link
            ]);

        $this->mailer->send($email);
    }
}