<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\TransactionalEmail;

use CpCreation\VitiCore\Cart\Model\Cart;
use CpCreation\VitiCore\TransactionalEmail\Model\TransactionalEmailQueue;
use CpCreation\VitiCore\TransactionalEmail\Repository\TransactionalEmailQueueRepository;
use CpCreation\VitiCore\TransactionalEmail\Repository\TransactionalEmailRepository;

final readonly class TransactionalEmailScheduler
{
    public function __construct(
        private TransactionalEmailRepository $transactionalEmailRepository,
        private TransactionalEmailQueueRepository $queueRepository,
    ) {
    }

    /**
     * @return list<TransactionalEmailQueue>
     */
    public function scheduleOrderPaid(Cart $cart): array
    {
        return $this->scheduleCartTrigger($cart, TransactionalEmailTrigger::ORDER_PAID);
    }

    /**
     * @return list<TransactionalEmailQueue>
     */
    public function scheduleCartTrigger(Cart $cart, string $triggerEvent): array
    {
        $payedAt = $cart->getCartCheckout()?->getPayedAt();
        $orderedAt = $cart->getCartCheckout()?->getOrderedAt();
        $initiatedAt = $cart->getCartCheckout()?->getInitiatedAt();

        $actionAt = match ($triggerEvent) {
            TransactionalEmailTrigger::PAYMENT_INITIATED => $initiatedAt,
            TransactionalEmailTrigger::ORDER_CREATED => $orderedAt,
            TransactionalEmailTrigger::ORDER_PAID => $payedAt,
            default => null,
        };

        if (!$actionAt instanceof \DateTimeInterface) {
            return [];
        }

        return $this->schedule(
            $triggerEvent,
            TransactionalEmailQueue::RELATED_TYPE_CART,
            $cart->getId()->toString(),
            $cart->getEmail(),
            \DateTimeImmutable::createFromInterface($actionAt),
            [
                'cart_id' => $cart->getId()->toString(),
                'cart_token' => $cart->getToken(),
                'locale' => $cart->getLocale(),
            ],
        );
    }

    /**
     * @param array<string, scalar|null> $context
     *
     * @return list<TransactionalEmailQueue>
     */
    public function schedule(
        string $triggerEvent,
        string $relatedType,
        string $relatedId,
        ?string $recipientEmail,
        \DateTimeImmutable $actionAt,
        array $context = [],
    ): array {
        $created = [];
        foreach ($this->transactionalEmailRepository->findEnabledByTrigger($triggerEvent) as $transactionalEmail) {
            if (null !== $this->queueRepository->findExisting($transactionalEmail, $relatedType, $relatedId)) {
                continue;
            }

            $scheduledAt = $actionAt->modify('+'.$transactionalEmail->getDelayDays().' days');
            $queue = new TransactionalEmailQueue(
                $transactionalEmail,
                $triggerEvent,
                $relatedType,
                $relatedId,
                $recipientEmail,
                $scheduledAt,
                $context,
            );

            $this->queueRepository->persist($queue);
            $created[] = $queue;
        }

        return $created;
    }
}
