<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\Marketing;

use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\Cart\Repository\CartRepository;
use CpCreation\VitiCore\Cart\Repository\PromoRepository;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartReminder;
use CpCreation\VitiCore\Marketing\Model\AbandonedCartRule;
use CpCreation\VitiCore\Marketing\Repository\AbandonedCartReminderRepository;

final readonly class AbandonedCartReminderIssuer
{
    public function __construct(
        private AbandonedCartReminderRepository $reminderRepository,
        private CartRepository $cartRepository,
        private PromoRepository $promoRepository,
        private AbandonedCartPromoFactory $promoFactory,
    ) {}

    public function issue(
        AbandonedCartRule $rule,
        Cart $cart,
        string $recipientEmail,
        ?\DateTimeImmutable $now = null,
    ): IssuedAbandonedCartReminder {
        $now ??= new \DateTimeImmutable();
        $expiresAt = $now->modify(sprintf('+%d days', $rule->getValidityDays()));
        $token = self::createToken();
        $promo = $this->promoFactory->create($rule, $cart, $recipientEmail, $now, $expiresAt);

        if (null !== $promo) {
            $this->promoRepository->persist($promo);
        }

        if ($cart->getExpiresAt() < $expiresAt) {
            $cart->setExpiresAt($expiresAt);
            $this->cartRepository->persist($cart);
        }

        $reminder = new AbandonedCartReminder(
            cart: $cart,
            rule: $rule,
            promo: $promo,
            recipientEmail: $recipientEmail,
            tokenHash: hash('sha256', $token),
            scheduledAt: $now,
            expiresAt: $expiresAt,
        );
        $this->reminderRepository->persist($reminder);

        return new IssuedAbandonedCartReminder($reminder, $token);
    }

    private static function createToken(): string
    {
        return rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '=');
    }
}
