<?php

use App\Services\Mail\MailTlsPolicy;
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;

/**
 * The single place that decides what "ssl", "tls", and "none" mean on the
 * wire. MailboxTransport (real sends) and MailboxTester (the test-send
 * button) used to each re-derive the "ssl, or port 465 ⇒ implicit TLS" half
 * of this on their own — this table is what replaces both copies, so it is
 * pinned down here independently of either caller.
 */
it('maps a stored encryption choice and port to the three EsmtpTransport switches', function (
    string $encryption,
    int $port,
    bool $implicit,
    bool $autoTls,
    bool $requireTls,
) {
    $policy = MailTlsPolicy::for($encryption, $port);

    expect($policy->implicit)->toBe($implicit)
        ->and($policy->autoTls)->toBe($autoTls)
        ->and($policy->requireTls)->toBe($requireTls);
})->with([
    // encryption, port, implicit, autoTls, requireTls

    // 'ssl' is implicit TLS from the first byte, on any port — unchanged
    // from before this fix.
    'ssl on the submission port' => ['ssl', 587, true, true, true],
    'ssl on the SMTPS port' => ['ssl', 465, true, true, true],

    // Port 465 forces implicit TLS regardless of the stored encryption
    // setting, exactly as before this fix: a server listening there speaks
    // TLS from byte one and will not answer a plaintext EHLO, so a
    // mismatched setting must not turn into a hang.
    'tls on the SMTPS port defers to the port' => ['tls', 465, true, true, true],
    'none on the SMTPS port defers to the port' => ['none', 465, true, true, true],

    // 'tls' is the fix: STARTTLS is REQUIRED, not merely attempted. autoTls
    // must stay on too, or the STARTTLS upgrade requireTls checks for would
    // never be attempted in the first place.
    'tls on the submission port' => ['tls', 587, false, true, true],
    'tls on a custom port' => ['tls', 2525, false, true, true],

    // 'none' is the other half of the fix: no implicit wrap, and autoTls
    // OFF — otherwise a server that happens to offer STARTTLS would still
    // silently upgrade despite the operator's explicit choice.
    'none on the submission port' => ['none', 587, false, false, false],
    'none on a custom port' => ['none', 2525, false, false, false],

    // Blank or unrecognised values (a legacy row predating the in:tls,ssl,none
    // validation, or one that decoded to something unexpected) fall to the
    // same shape as 'none': no implicit wrap, no silent upgrade, no
    // spurious failure for a value nobody explicitly chose as 'tls'.
    'blank falls back to the none shape' => ['', 587, false, false, false],
    'garbage falls back to the none shape' => ['garbage', 587, false, false, false],
]);

it('applies autoTls and requireTls to an already-built transport', function () {
    $transport = new EsmtpTransport('mail.example.test', 587, false);

    $policy = MailTlsPolicy::for('tls', 587);
    $returned = $policy->apply($transport);

    expect($returned)->toBe($transport) // fluent — the caller chains straight through
        ->and($transport->isAutoTls())->toBeTrue()
        ->and($transport->isTlsRequired())->toBeTrue();
});
