<?php

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Security;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\Model\RegisterRequest;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\RegisterType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Command\NotificationCommand;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Enum\PushLevel;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Behavior\HasTemplateOverride;
use CpCreation\VitiCore\User\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

#[AsLiveComponent('security:RegisterForm', template: '@components/security/RegisterForm.html.twig')]
final class RegisterForm extends AbstractController
{
    use ComponentWithFormTrait;
    use DefaultActionTrait;
    use HasTemplateOverride;

    private const SESSION_REGISTER_EMAIL = 'security.register.email';
    private const SESSION_REGISTER_MARKETING = 'security.register.marketing_opt_in';

    public function __construct(
        private readonly UserRepository $userRepository,
        private readonly RequestStack $requestStack,
        private readonly MessageBusInterface $commandSimpleBus,
        private readonly TranslatorInterface $translator,
    ) {
    }

    protected function instantiateForm(): FormInterface
    {
        return $this->createForm(RegisterType::class, new RegisterRequest());
    }

    #[LiveAction]
    public function submitRegister(): ?Response
    {
        try {
            $this->submitForm();
        } catch (UnprocessableEntityHttpException) {
            $this->notifyFirstFormError();

            return null;
        }

        $data = $this->form?->getData();
        if (!$data instanceof RegisterRequest) {
            return null;
        }

        $email = $this->normalizeEmail($data->getEmail());

        if (null !== $this->userRepository->findVerifiedByEmail($email)) {
            $this->notify($this->translator->trans('security.error.account_exists', [], 'messages'), PushLevel::ERROR);

            return null;
        }

        $session = $this->getSession();
        $session?->set(self::SESSION_REGISTER_EMAIL, $email);
        $session?->set(self::SESSION_REGISTER_MARKETING, $data->isMarketingOptIn());

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

    public function canSubmit(): bool
    {
        $email = $this->formValues['email'] ?? null;

        return \is_string($email) && false !== filter_var($email, \FILTER_VALIDATE_EMAIL);
    }

    private function getSession(): ?SessionInterface
    {
        return $this->requestStack->getCurrentRequest()?->getSession();
    }

    private function notifyFirstFormError(): void
    {
        $error = $this->form?->getErrors(true)->current();
        if (null === $error) {
            return;
        }

        $this->notify($error->getMessage(), PushLevel::ERROR);
    }

    private function notify(string $message, PushLevel $level): void
    {
        $this->commandSimpleBus->dispatch(new NotificationCommand(
            message: $message,
            level: $level,
        ));
    }

    private function normalizeEmail(?string $email): string
    {
        return mb_strtolower(mb_trim((string) $email));
    }
}
