<?php

namespace App\Controller;

use App\Repository\UserRepository;
use App\Service\MailerService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Twig\Environment;

class ForgotPasswordController extends AbstractController
{
    #[Route('/mot-de-passe-oublie', name: 'app_forgot_password', methods: ['GET', 'POST'])]
    public function index(
        Request $request,
        UserRepository $userRepository,
        MailerService $mailer,
        EntityManagerInterface $em,
        UserPasswordHasherInterface $passwordHasher,
        Environment $twig,
    ): Response {
        $session = $request->getSession();
        $step = $session->get('reset_step', 'email');
        $error = null;
        $success = null;

        if ('POST' === $request->getMethod()) {
            $action = $request->request->getString('action');

            if ('send_code' === $action) {
                [$step, $success] = $this->handleSendCode($request, $userRepository, $mailer, $twig);
            } elseif ('reset' === $action) {
                $result = $this->handleReset($request, $userRepository, $passwordHasher, $em, $mailer, $twig);

                if ($result['redirect']) {
                    return $this->redirectToRoute('app_home');
                }

                $step = $result['step'];
                $error = $result['error'];
            }
        }

        return $this->render('security/forgot_password.html.twig', [
            'step' => $step,
            'email' => $session->get('reset_email', ''),
            'error' => $error,
            'success' => $success,
        ]);
    }

    /**
     * @return array{string, string}
     */
    private function handleSendCode(Request $request, UserRepository $userRepository, MailerService $mailer, Environment $twig): array
    {
        $session = $request->getSession();
        $email = trim($request->request->getString('email'));
        $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);

        $session->set('reset_code', $code);
        $session->set('reset_email', $email);
        $session->set('reset_expires', time() + 600);
        $session->set('reset_step', 'code');

        $user = $userRepository->findOneBy(['email' => $email]);
        if (null !== $user) {
            $mailer->sendEmail(
                $email,
                'CRM E-Cosplay - Code de reinitialisation',
                $twig->render('emails/forgot_password_code.html.twig', ['code' => $code]),
                null,
                null,
                false,
            );
        }

        return ['code', 'Si un compte existe avec cette adresse, un code vous a ete envoye par email.'];
    }

    /**
     * @return array{redirect: bool, step: string, error: string|null}
     */
    private function handleReset(Request $request, UserRepository $userRepository, UserPasswordHasherInterface $passwordHasher, EntityManagerInterface $em, MailerService $mailer, Environment $twig): array
    {
        $session = $request->getSession();
        $inputCode = trim($request->request->getString('code'));
        $newPassword = $request->request->getString('password');
        $sessionCode = $session->get('reset_code');
        $sessionEmail = $session->get('reset_email');
        $expires = $session->get('reset_expires', 0);

        $error = $this->validateResetInput($session, $inputCode, $newPassword, $sessionCode, $expires);
        if (null !== $error) {
            return $error;
        }

        $user = $userRepository->findOneBy(['email' => $sessionEmail]);
        if (null !== $user) {
            $user->setPassword($passwordHasher->hashPassword($user, $newPassword));
            $em->flush();

            $mailer->sendEmail(
                $sessionEmail,
                'CRM E-Cosplay - Mot de passe modifie',
                $twig->render('emails/password_changed.html.twig'),
                null,
                null,
                false,
            );
        }

        $this->clearResetSession($session);
        $this->addFlash('success', 'Votre mot de passe a ete modifie avec succes.');

        return ['redirect' => true, 'step' => 'email', 'error' => null];
    }

    /**
     * @return array{redirect: bool, step: string, error: string}|null
     */
    private function validateResetInput(object $session, string $inputCode, string $newPassword, string $sessionCode, int $expires): ?array
    {
        if (time() > $expires) {
            $this->clearResetSession($session);

            return ['redirect' => false, 'step' => 'email', 'error' => 'Le code a expire. Veuillez recommencer.'];
        }

        $error = match (true) {
            !hash_equals($sessionCode, $inputCode) => 'Le code est incorrect.',
            \strlen($newPassword) < 8 => 'Le mot de passe doit contenir au moins 8 caracteres.',
            default => null,
        };

        return null !== $error ? ['redirect' => false, 'step' => 'code', 'error' => $error] : null;
    }

    private function clearResetSession(object $session): void
    {
        $session->remove('reset_step');
        $session->remove('reset_code');
        $session->remove('reset_email');
        $session->remove('reset_expires');
    }
}
