<?php declare(strict_types=1);
/*
 * This file is part of the SplendidBear Websites' projects.
 *
 * Copyright (c) 2026 @ www.splendidbear.org
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Controller;

use App\Entity\User;
use App\Form\ForgotPasswordFormType;
use App\Form\RegistrationFormType;
use App\Form\ResetPasswordFormType;
use App\Repository\UserRepository;
use App\Service\Email\SendActivationEmailService;
use App\Service\Email\SendPasswordResetEmailService;
use App\Service\Email\SendUserActivationNotificationService;
use App\Service\Email\SendUserRegistrationNotificationService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use LogicException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

/**
 * Class SecurityController
 *
 * @package  App\Controller
 * @author   Lang <https://www.splendidbear.org>
 * @category Class
 * @license  https://www.gnu.org/licenses/lgpl-3.0.en.html GNU Lesser General Public License
 * @link     www.splendidbear.org
 * @since    2026. 04. 11.
 */
#[AsController]
class SecurityController extends AbstractController
{
    public function __construct(
        private readonly EntityManagerInterface                  $em,
        private readonly RequestStack                            $requestStack,
        private readonly UserRepository                          $userRepository,
        private readonly UserPasswordHasherInterface             $passwordHasher,
        private readonly AuthenticationUtils                     $authenticationUtils,
        private readonly SendActivationEmailService              $activationEmail,
        private readonly SendPasswordResetEmailService           $passwordResetEmail,
        private readonly SendUserActivationNotificationService   $activationNotificationEmail,
        private readonly SendUserRegistrationNotificationService $registrationNotificationEmail,
    ) {
    }

    #[Route('/login', name: 'MineSeekerBundle_login')]
    public function login(): Response
    {
        if ($this->getUser()) {
            return $this->redirectToRoute('MineSeekerBundle_homepage');
        }

        return $this->render('Security/login.html.twig', [
            'last_username' => $this->authenticationUtils->getLastUsername(),
            'error'         => $this->authenticationUtils->getLastAuthenticationError(),
        ]);
    }

    #[Route('/logout', name: 'MineSeekerBundle_logout', methods: ['POST'])]
    public function logout(): never
    {
        throw new LogicException('This action is intercepted by the security firewall.');
    }

    #[Route('/register', name: 'MineSeekerBundle_register')]
    public function register(): Response
    {
        if ($this->getUser()) {
            return $this->redirectToRoute('MineSeekerBundle_homepage');
        }

        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($this->requestStack->getCurrentRequest());

        if ($form->isSubmitted() && $form->isValid()) {
            $token = bin2hex(random_bytes(32));

            $user->isVerified = false;
            $user->verificationToken = $token;
            $user->password = $this->passwordHasher->hashPassword($user, $form->get('plainPassword')->getData());

            $this->em->persist($user);
            $this->em->flush();

            $activationUrl = $this->generateUrl(
                'MineSeekerBundle_activate',
                ['token' => $token],
                UrlGeneratorInterface::ABSOLUTE_URL,
            );

            /** Ensure HTTPS scheme in production */
            if ($this->getParameter('kernel.environment') === 'prod') {
                $activationUrl = str_replace('http://', 'https://', $activationUrl);
            }

            $this->activationEmail->send($user, $activationUrl);
            $this->registrationNotificationEmail->send($user, new DateTime());

            $this->addFlash('verify_email', $user->email);

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

        return $this->render('Security/register.html.twig', ['form' => $form]);
    }

    #[Route('/forgot-password', name: 'MineSeekerBundle_forgot_password')]
    public function forgotPassword(): Response
    {
        if ($this->getUser()) {
            return $this->redirectToRoute('MineSeekerBundle_homepage');
        }

        $form = $this->createForm(ForgotPasswordFormType::class);
        $form->handleRequest($this->requestStack->getCurrentRequest());

        if ($form->isSubmitted() && $form->isValid()) {
            $email = $form->get('email')->getData();
            $user = $this->userRepository->findOneByEmail($email);

            if ($user && $user->isVerified) {
                $token = bin2hex(random_bytes(32));
                $user->resetToken = $token;
                $user->resetTokenExpiresAt = new DateTime('+1 hour');
                $this->em->flush();

                $resetUrl = $this->generateUrl(
                    'MineSeekerBundle_reset_password',
                    ['token' => $token],
                    UrlGeneratorInterface::ABSOLUTE_URL,
                );

                /** Ensure HTTPS scheme in production */
                if ($this->getParameter('kernel.environment') === 'prod') {
                    $resetUrl = str_replace('http://', 'https://', $resetUrl);
                }

                $this->passwordResetEmail->send($email, $user->getUsername(), $resetUrl);
            }

            $this->addFlash('reset_sent', $email);

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

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

    #[Route('/reset-password/{token}', name: 'MineSeekerBundle_reset_password')]
    public function resetPassword(string $token): Response
    {
        $user = $this->userRepository->findOneByResetToken($token);

        if (!$user || $user->resetTokenExpiresAt < new DateTime()) {
            $this->addFlash('error', 'This password reset link is invalid or has expired.');
            return $this->redirectToRoute('MineSeekerBundle_forgot_password');
        }

        $form = $this->createForm(ResetPasswordFormType::class);
        $form->handleRequest($this->requestStack->getCurrentRequest());

        if ($form->isSubmitted() && $form->isValid()) {
            $user->password = $this->passwordHasher->hashPassword($user, $form->get('plainPassword')->getData());
            $user->resetToken = null;
            $user->resetTokenExpiresAt = null;

            $this->em->flush();

            $this->addFlash('success', 'Your password has been reset. You can now sign in.');

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

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

    #[Route('/activate/{token}', name: 'MineSeekerBundle_activate')]
    public function activate(string $token): Response
    {
        $user = $this->em->getRepository(User::class)->findOneBy(['verificationToken' => $token]);

        if (!$user) {
            $this->addFlash('error', 'This activation link is invalid or has already been used.');
            return $this->redirectToRoute('MineSeekerBundle_login');
        }

        $user->isVerified = true;
        $user->verificationToken = null;
        $this->em->flush();

        $this->activationNotificationEmail->send($user, new DateTime());

        $this->addFlash('success', 'Your account is now active. Welcome, ' . $user->getUsername() . '!');

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