<?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\LoginType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\Model\LoginRequest;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Command\NotificationCommand;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Notification\Enum\PushLevel;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Security\AccountActivationService;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Twig\Components\Behavior\HasTemplateOverride;
use CpCreation\VitiCore\Cart\CartService;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\User\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Contracts\Translation\TranslatorInterface;
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\Attribute\LiveProp;
use Symfony\UX\LiveComponent\ComponentWithFormTrait;
use Symfony\UX\LiveComponent\DefaultActionTrait;

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

    #[LiveProp(writable: true)]
    public ?string $targetPath = null;

    public function __construct(
        private readonly UserRepository $userRepository,
        private readonly UserPasswordHasherInterface $passwordHasher,
        private readonly Security $security,
        private readonly CartService $cartService,
        private readonly CartRepository $cartRepository,
        private readonly MessageBusInterface $commandSimpleBus,
        private readonly AccountActivationService $accountActivationService,
        private readonly TranslatorInterface $translator,
    ) {
    }

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

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

            return null;
        }

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

        $email = $this->normalizeEmail($data->getEmail());
        $user = $this->userRepository->findOneBy(['email' => $email]);

        if (null === $user || !$this->passwordHasher->isPasswordValid($user, (string) $data->getPassword())) {
            $this->notify($this->translator->trans('security.error.invalid_credentials', [], 'messages'), PushLevel::ERROR);

            return null;
        }

        if (!$user->isVerified()) {
            $emailSent = $this->accountActivationService->sendActivationEmail($user);
            $this->notify(
                $this->translator->trans(
                    $emailSent
                        ? 'security.activation.sent'
                        : 'security.activation.recently_sent',
                    [],
                    'messages'
                ),
                PushLevel::ERROR
            );

            return null;
        }

        $badges = [];

        if ($data->isRememberMe()) {
            $badges[] = (new RememberMeBadge())->enable();
        }

        $this->cartService->claimSessionCartForUser($user);
        $this->cartRepository->attachGuestCompletedOrdersToUserByEmail($user);

        $response = $this->security->login($user, 'form_login', 'app', $badges);

        if (\is_string($this->targetPath) && '' !== $this->targetPath && str_starts_with($this->targetPath, '/')) {
            return $this->redirect($this->targetPath);
        }

        if (null !== $response) {
            return $response;
        }

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

    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));
    }
}
