<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\Notification;

use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Contao\CoreBundle\Framework\ContaoFramework;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\Offer\Base;
use Ferienpass\CoreBundle\Export\Offer\ICal\ICalExport;
use Ferienpass\CoreBundle\Notifier\Message\EmailMessage;
use Ferienpass\CoreBundle\Notifier\Mime\NotificationEmail;
use Ferienpass\CoreBundle\Repository\EditionTaskRepository;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\Notifier\Message\EmailMessage as SymfonyEmailMessage;
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\Notification\EmailNotificationInterface;
use Symfony\Component\Notifier\Notification\SmsNotificationInterface;
use Symfony\Component\Notifier\Recipient\EmailRecipientInterface;
use Symfony\Component\Notifier\Recipient\RecipientInterface;
use Symfony\Component\Notifier\Recipient\SmsRecipientInterface;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class AttendanceNewlyConfirmedNotification extends AbstractNotification implements NotificationInterface, EditionAwareNotificationInterface, EmailNotificationInterface, SmsNotificationInterface
{
    use ActionUrlTrait;

    private Attendance $attendance;

    public function __construct(private readonly ICalExport $iCalExport, private readonly EventDispatcherInterface $dispatcher, private readonly ContaoFramework $contaoFramework, private readonly EditionTaskRepository $tasks, private readonly VirtualFilesystemInterface $attachmentsStorage, #[Autowire(param: 'kernel.project_dir')] private readonly string $projectDir)
    {
        parent::__construct();
    }

    public static function getName(): string
    {
        return 'attendance_newly_confirmed';
    }

    public function getChannels(RecipientInterface $recipient): array
    {
        $channels = [];

        if ($recipient instanceof EmailRecipientInterface && $recipient->getEmail()) {
            $channels[] = 'email';
        }

        $date = $this->attendance->getOffer()->getDateBegin();
        $urgent = new \DateTimeImmutable('+30 hours');

        if ($recipient instanceof SmsRecipientInterface && $this->getSmsText() && $recipient->getPhone() && $date && $date < $urgent) {
            $channels[] = 'sms';
        }

        return $channels;
    }

    public function attendance(Attendance $attendance): static
    {
        $this->attendance = $attendance;

        return $this;
    }

    public function getContext(): array
    {
        return array_merge(parent::getContext(), [
            'attendance' => $this->attendance,
            'offer' => $this->attendance->getOffer(),
            'participant' => $this->attendance->getParticipant(),
            'offer_fee' => $this->attendance->getOffer()->getFeePayable($this->attendance->getParticipant(), $this->dispatcher),
        ]);
    }

    public static function getAvailableTokens(): array
    {
        return array_merge(parent::getAvailableTokens(), ['attendance']);
    }

    public function asEmailMessage(EmailRecipientInterface $recipient, ?string $transport = null): ?SymfonyEmailMessage
    {
        $this->contaoFramework->initialize();

        return EmailMessage::fromFerienpassNotification($this, $recipient, function (NotificationEmail $email) {
            /** @var Base $offer */
            $offer = $this->attendance->getOffer();

            $email->attach($this->iCalExport->generate([$offer], stream: true), \sprintf('%s.ics', $offer->getAlias()));

            if (null !== $this->actionUrl) {
                $email->action('email.attendance_newly_confirmed.open', $this->actionUrl);
            }

            if ($offer->requiresAgreementLetter() && ($attachment = $offer->getAgreementLetter()) && ($file = $this->attachmentsStorage->get($attachment->getAttachment()->getUuid()))) {
                $email->attach($this->attachmentsStorage->readStream($attachment->getAttachment()->getUuid()), $file->getName());
            }
        });
    }

    public function asSmsMessage(SmsRecipientInterface $recipient, ?string $transport = null): ?SmsMessage
    {
        return new SmsMessage($recipient->getPhone(), $this->getSmsText());
    }
}
