<?php

declare(strict_types=1);

use App\Domain\Common\ValueObject\Email;
use App\Framework\Mail\EmailList;
use App\Framework\Mail\Message;
use App\Framework\Mail\Priority;

describe('Message', function () {
    it('creates a basic message with required fields', function () {
        $from = new Email('sender@example.com');
        $to = new EmailList(new Email('recipient@example.com'));
        $subject = 'Test Subject';
        $body = 'Test body content';

        $message = new Message(
            from: $from,
            subject: $subject,
            body: $body,
            to: $to
        );

        expect($message->from)->toBe($from);
        expect($message->subject)->toBe($subject);
        expect($message->body)->toBe($body);
        expect($message->to)->toBe($to);
        expect($message->priority)->toBe(Priority::NORMAL);
        expect($message->cc->isEmpty())->toBeTrue();
        expect($message->bcc->isEmpty())->toBeTrue();
        expect($message->attachments)->toBeEmpty();
        expect($message->headers)->toBeEmpty();
        expect($message->replyTo)->toBeNull();
    });

    it('creates a message with HTML body', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            htmlBody: '<h1>HTML Content</h1>',
            to: new EmailList(new Email('recipient@example.com'))
        );

        expect($message->htmlBody)->toBe('<h1>HTML Content</h1>');
        expect($message->body)->toBe('');
        expect($message->hasHtmlBody())->toBeTrue();
    });

    it('creates a message with both text and HTML body', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Plain text',
            htmlBody: '<p>HTML content</p>',
            to: new EmailList(new Email('recipient@example.com'))
        );

        expect($message->body)->toBe('Plain text');
        expect($message->htmlBody)->toBe('<p>HTML content</p>');
        expect($message->hasHtmlBody())->toBeTrue();
    });

    it('throws exception when both body and HTML body are empty', function () {
        expect(fn () => new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            to: new EmailList(new Email('recipient@example.com'))
        ))->toThrow(InvalidArgumentException::class, 'Either body or HTML body is required');
    });

    it('throws exception when to list is empty', function () {
        expect(fn () => new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList()
        ))->toThrow(InvalidArgumentException::class, 'At least one recipient is required');
    });

    it('creates message with CC and BCC recipients', function () {
        $cc = new EmailList(new Email('cc@example.com'));
        $bcc = new EmailList(new Email('bcc@example.com'));

        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com')),
            cc: $cc,
            bcc: $bcc
        );

        expect($message->cc)->toBe($cc);
        expect($message->bcc)->toBe($bcc);
    });

    it('creates message with high priority', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Urgent',
            body: 'Urgent message',
            to: new EmailList(new Email('recipient@example.com')),
            priority: Priority::HIGH
        );

        expect($message->priority)->toBe(Priority::HIGH);
    });

    it('creates message with custom headers', function () {
        $headers = ['X-Custom-Header' => 'custom-value'];

        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com')),
            headers: $headers
        );

        expect($message->headers)->toBe($headers);
    });

    it('creates message with reply-to address', function () {
        $replyTo = new Email('noreply@example.com');

        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com')),
            replyTo: $replyTo
        );

        expect($message->replyTo)->toBe($replyTo);
    });

    it('provides fluent withTo method', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('original@example.com'))
        );

        $newMessage = $message->withTo(new Email('new@example.com'));

        expect($newMessage)->not->toBe($message);
        expect($newMessage->to->toString())->toBe('new@example.com');
        expect($message->to->toString())->toBe('original@example.com');
    });

    it('provides fluent withCc method', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com'))
        );

        $newMessage = $message->withCc(new Email('cc@example.com'));

        expect($newMessage)->not->toBe($message);
        expect($newMessage->cc->toString())->toBe('cc@example.com');
        expect($message->cc->isEmpty())->toBeTrue();
    });

    it('provides fluent withBcc method', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com'))
        );

        $newMessage = $message->withBcc(new Email('bcc@example.com'));

        expect($newMessage)->not->toBe($message);
        expect($newMessage->bcc->toString())->toBe('bcc@example.com');
        expect($message->bcc->isEmpty())->toBeTrue();
    });

    it('provides fluent withSubject method', function () {
        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Original Subject',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com'))
        );

        $newMessage = $message->withSubject('New Subject');

        expect($newMessage)->not->toBe($message);
        expect($newMessage->subject)->toBe('New Subject');
        expect($message->subject)->toBe('Original Subject');
    });

    it('gets all recipients (to, cc, bcc)', function () {
        $to = EmailList::fromArray([new Email('to@example.com')]);
        $cc = new EmailList(new Email('cc@example.com'));
        $bcc = new EmailList(new Email('bcc@example.com'));

        $message = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: $to,
            cc: $cc,
            bcc: $bcc
        );

        $allRecipients = $message->getAllRecipients();

        expect($allRecipients->count())->toBe(3);
        expect($allRecipients->contains(new Email('to@example.com')))->toBeTrue();
        expect($allRecipients->contains(new Email('cc@example.com')))->toBeTrue();
        expect($allRecipients->contains(new Email('bcc@example.com')))->toBeTrue();
    });

    it('detects if message has attachments', function () {
        $messageWithoutAttachments = new Message(
            from: new Email('sender@example.com'),
            subject: 'Test',
            body: 'Test body',
            to: new EmailList(new Email('recipient@example.com'))
        );

        expect($messageWithoutAttachments->hasAttachments())->toBeFalse();

        // Note: We can't easily test with real attachments without mocking the Storage and file system
        // This would be covered in integration tests
    });
});
