<?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\Tests\Entity;

use Ferienpass\CoreBundle\Entity\SentEmail;
use Ferienpass\CoreBundle\Notifier\Mime\NotificationEmail;
use PHPUnit\Framework\TestCase;

final class SentEmailTest extends TestCase
{
    public function testFromNotificationEmailStoresBasicData(): void
    {
        $email = new NotificationEmail('test_type');
        $email->from('sender@example.com');
        $email->to('recipient@example.com');
        $email->subject('Test Subject');
        $email->text('Hello text');
        $email->html('<p>Hello html</p>');

        $entity = SentEmail::fromNotificationEmail($email, 'msg-id-123');

        self::assertSame('msg-id-123', $entity->getMessageId());
        self::assertSame('sender@example.com', $entity->getFrom());
        self::assertSame('recipient@example.com', $entity->getTo());
        self::assertSame('Test Subject', $entity->getSubject());
        self::assertSame('Hello text', $entity->getText());
        self::assertSame('<p>Hello html</p>', $entity->getHtml());
        self::assertSame([], $entity->getAttachments());
    }

    public function testFromNotificationEmailWithNoAddresses(): void
    {
        $email = new NotificationEmail('welcome');

        $entity = SentEmail::fromNotificationEmail($email, 'msg-xyz');

        self::assertNull($entity->getFrom());
        self::assertNull($entity->getTo());
        self::assertNull($entity->getSubject());
    }

    /**
     * The columns the Postausgang search actually matches — they exist so the query
     * never has to touch the emailData blob, and are read via DQL rather than getters.
     */
    public function testFromNotificationEmailFillsSearchColumns(): void
    {
        $email = new NotificationEmail('test_type');
        $email->to('recipient@example.com');
        $email->subject('Test Subject');

        $entity = SentEmail::fromNotificationEmail($email, 'msg-id-123');

        self::assertSame('recipient@example.com', self::column($entity, 'toAddress'));
        self::assertSame('Test Subject', self::column($entity, 'subject'));
    }

    public function testSearchColumnsStayNullWithoutAddressOrSubject(): void
    {
        $entity = SentEmail::fromNotificationEmail(new NotificationEmail('welcome'), 'msg-xyz');

        self::assertNull(self::column($entity, 'toAddress'));
        self::assertNull(self::column($entity, 'subject'));
    }

    public function testSearchColumnsAreClippedToColumnLength(): void
    {
        $email = new NotificationEmail('test_type');
        $email->to('recipient@example.com');
        $email->subject(str_repeat('ä', 300));

        $entity = SentEmail::fromNotificationEmail($email, 'msg-id-123');

        self::assertSame(255, mb_strlen((string) self::column($entity, 'subject')));
        // The blob keeps the full value — only the search column is clipped.
        self::assertSame(300, mb_strlen((string) $entity->getSubject()));
    }

    public function testSetToNameStoresTheName(): void
    {
        $entity = SentEmail::fromNotificationEmail(new NotificationEmail('welcome'), 'msg');

        $entity->setToName('Erika Mustermann');

        self::assertSame('Erika Mustermann', $entity->getToName());
    }

    /**
     * User::getName() joins first and last name unconditionally, so a nameless account
     * yields " ". Storing that would shadow the outbox's fallback to the address.
     */
    public function testSetToNameNormalisesBlankToNull(): void
    {
        $entity = SentEmail::fromNotificationEmail(new NotificationEmail('welcome'), 'msg');

        $entity->setToName(' ');

        self::assertNull($entity->getToName());
    }

    private static function column(SentEmail $entity, string $property): ?string
    {
        $reflection = new \ReflectionProperty(SentEmail::class, $property);

        return $reflection->getValue($entity);
    }
}
