<?php

declare(strict_types=1);

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

use CpCreation\VitiCore\Bridge\Symfony\Bundle\Event\UserAccountVerifiedEvent;
use CpCreation\VitiCore\Product\Repository\ProductPriceGroupRepository;
use CpCreation\VitiCore\Bridge\Symfony\Bundle\Utils\Mailer;
use CpCreation\VitiCore\User\Model\User;
use CpCreation\VitiCore\User\Repository\UserRepository;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

final class AccountActivationService
{
    private const EXPIRATION_INTERVAL = '+24 hours';
    private const RESEND_COOLDOWN = '-5 minutes';

    public function __construct(
        private readonly UserRepository $userRepository,
        private readonly ProductPriceGroupRepository $productPriceGroupRepository,
        private readonly Mailer $mailer,
        private readonly EventDispatcherInterface $eventDispatcher,
    ) {
    }

    public function sendActivationEmail(User $user, bool $force = false): bool
    {
        if ($user->isVerified()) {
            return false;
        }

        if (!$force && !$this->canResend($user)) {
            return false;
        }

        $now = new \DateTimeImmutable();
        $user->setEmailVerificationToken(bin2hex(random_bytes(32)));
        $user->setEmailVerificationRequestedAt($now);
        $user->setEmailVerificationExpiresAt($now->modify(self::EXPIRATION_INTERVAL));
        $this->userRepository->save($user);
        $this->mailer->sendAccountActivation($user);

        return true;
    }

    public function canResend(User $user): bool
    {
        $requestedAt = $user->getEmailVerificationRequestedAt();

        if (null === $requestedAt) {
            return true;
        }

        return $requestedAt <= new \DateTimeImmutable(self::RESEND_COOLDOWN);
    }

    public function verify(User $user): void
    {
        if (null === $user->getGroup()) {
            $user->setGroup($this->productPriceGroupRepository->getGroupByDefault());
        }

        $user->setIsVerified(true);
        $user->setEmailVerificationToken(null);
        $user->setEmailVerificationRequestedAt(null);
        $user->setEmailVerificationExpiresAt(null);
        $this->userRepository->save($user);
        $this->eventDispatcher->dispatch(new UserAccountVerifiedEvent($user));
    }

    public function isVerificationExpired(User $user): bool
    {
        $expiresAt = $user->getEmailVerificationExpiresAt();

        return null === $expiresAt || $expiresAt < new \DateTimeImmutable();
    }
}
