<?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\EventListener;

use Contao\CoreBundle\Filesystem\VirtualFilesystemInterface;
use Ferienpass\CoreBundle\Settings\PageConfigManager;
use Psr\Log\LoggerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Mailer\Event\MessageEvent;
use Symfony\Component\Mime\Part\DataPart;

/**
 * Embeds the tenant's logo into outgoing e-mail and exposes it to the template
 * as `logoSrc`.
 *
 * The logo has to be attached here rather than picked up in Twig, because the
 * template has no way to reach the message being rendered and no way to reach a
 * per-tenant file: `email.image('@images/logo_email.png')` resolves a Twig path
 * that is bound to the kernel at compile time, so on a shared build every
 * municipality would get the same logo — or none.
 *
 * Priority 10 puts this ahead of the mailer's own MessageListener (0), which is
 * what renders the body: the context has to carry `logoSrc` before Twig runs.
 *
 * An `apps/{id}/templates/email/_header.html.twig` that sets `logoSrc` itself
 * still wins — a template's own `{% set %}` shadows the context — so
 * single-tenant builds keep the logo they have today.
 */
#[AsEventListener(event: MessageEvent::class, priority: 10)]
class EmailLogoListener
{
    // A Content-ID is addr-spec shaped; Symfony rejects one without an "@".
    public const CONTENT_ID = 'logo@ferienpass';

    public function __construct(
        private readonly PageConfigManager $pageConfigManager,
        private readonly VirtualFilesystemInterface $logosStorage,
        private readonly LoggerInterface $logger,
    ) {
    }

    public function __invoke(MessageEvent $event): void
    {
        $message = $event->getMessage();

        if (!$message instanceof TemplatedEmail) {
            return;
        }

        $context = $message->getContext();

        // Already decided — either by an earlier pass over the same message or
        // by the caller. Never embed twice.
        if (\array_key_exists('logoSrc', $context)) {
            return;
        }

        $logo = $this->pageConfigManager->getPageConfig()->getLogo();
        $uuid = $logo?->getUuid();
        if (null === $uuid) {
            return;
        }

        try {
            $item = $this->logosStorage->get($uuid);
            if (null === $item) {
                return;
            }

            $part = new DataPart($this->logosStorage->readStream($uuid), $item->getName(), $item->getMimeType())
                ->asInline()
                ->setContentId(self::CONTENT_ID)
            ;
        } catch (\Throwable $e) {
            // A missing or unreadable logo must never stop the mail going out.
            $this->logger->warning('Could not embed the logo into an e-mail.', ['exception' => $e]);

            return;
        }

        $message->addPart($part);
        $message->context($context + ['logoSrc' => 'cid:'.self::CONTENT_ID]);
    }
}
