<?php

namespace CpCreation\VitiCore\Bridge\Symfony\Bundle\Controller\Admin;

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\ForgotPasswordType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\Model\ForgotPasswordRequest;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\Model\ResetPasswordRequest;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Form\Site\Security\ResetPasswordType;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Security\PasswordResetService;
use CpCreation\VitiCore\User\Model\User;
use CpCreation\VitiCore\User\Repository\UserRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

final class SecurityController extends AbstractController
{
    private const SESSION_RESET_PENDING_EMAIL = 'security.admin_reset_pending.email';

    public function __construct(
        private readonly RequestStack $requestStack,
    ) {
    }

    #[Route('/connexion', name: 'login')]
    public function login(Request $request, AuthenticationUtils $authUtils): Response
    {
        // get the login error if there is one
        $error = $authUtils->getLastAuthenticationError();

        // last username entered by the user
        $lastUsername = $authUtils->getLastUsername();

        return $this->render('@CpCreationVitiCore/admin/login.html.twig', [
            'last_username' => $lastUsername,
            'error' => $error,
            'target_path' => $this->resolveTargetPath($request),
        ]);
    }

    #[Route('/mot-de-passe-oublie', name: 'admin_forgot_password')]
    public function forgotPassword(
        Request $request,
        UserRepository $userRepository,
        PasswordResetService $passwordResetService,
    ): Response|RedirectResponse {
        $forgotPasswordRequest = new ForgotPasswordRequest();
        $form = $this->createForm(ForgotPasswordType::class, $forgotPasswordRequest);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $email = $this->normalizeEmail($forgotPasswordRequest->getEmail());
            $user = $userRepository->findOneBy(['email' => $email]);

            if ($this->canResetAdminPassword($user)) {
                $passwordResetService->sendResetEmail($user, false, 'admin_reset_password');
            }

            $request->getSession()->set(self::SESSION_RESET_PENDING_EMAIL, $email);

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

        return $this->render('@CpCreationVitiCore/admin/forgot_password.html.twig', [
            'form' => $form->createView(),
        ]);
    }

    #[Route('/mot-de-passe-oublie/email-envoye', name: 'admin_forgot_password_pending')]
    public function forgotPasswordPending(): Response
    {
        $session = $this->requestStack->getCurrentRequest()?->getSession();

        return $this->render('@CpCreationVitiCore/admin/forgot_password_pending.html.twig', [
            'reset_pending_email' => $session?->get(self::SESSION_RESET_PENDING_EMAIL),
        ]);
    }

    #[Route('/mot-de-passe-oublie/reinitialisation/{token}', name: 'admin_reset_password')]
    public function resetPassword(
        string $token,
        Request $request,
        UserRepository $userRepository,
        PasswordResetService $passwordResetService,
    ): Response|RedirectResponse {
        $user = $userRepository->findOneBy(['resetPasswordToken' => $token]);

        if (!$this->canResetAdminPassword($user)) {
            $this->addFlash('alert-danger', 'Ce lien de réinitialisation est invalide.');

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

        if ($passwordResetService->isExpired($user)) {
            $this->addFlash('alert-danger', 'Ce lien de réinitialisation a expiré.');

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

        $resetPasswordRequest = new ResetPasswordRequest();
        $form = $this->createForm(ResetPasswordType::class, $resetPasswordRequest, [
            'include_captcha' => false,
        ]);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $user->setPlainPassword($resetPasswordRequest->getPlainPassword());
            $passwordResetService->clear($user);
            $this->addFlash('alert-success', 'Votre mot de passe a été mis à jour. Vous pouvez vous connecter.');

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

        return $this->render('@CpCreationVitiCore/admin/reset_password.html.twig', [
            'form' => $form->createView(),
        ]);
    }

    private function canResetAdminPassword(?User $user): bool
    {
        return null !== $user && \in_array('ROLE_ADMIN', $user->getRoles(), true);
    }

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

    private function resolveTargetPath(Request $request): ?string
    {
        $targetPath = $request->getSession()->get('_security.admin.target_path');

        return \is_string($targetPath) && '' !== mb_trim($targetPath) ? $targetPath : null;
    }
}
