<?php
/**
 * Sends an email with an optional file attachment via SMTP.
 *
 * @param array  $cfg      Config array with smtp_host, smtp_port, smtp_user, smtp_password, mail_from
 * @param string $to       Recipient address
 * @param string $subject  Subject (plain UTF-8, will be encoded)
 * @param string $body     Plain-text body
 * @param array  $attach   Optional: ['path' => '/abs/path', 'name' => 'display.pdf', 'mime' => 'application/pdf']
 * @return array           ['ok' => bool, 'log' => string]
 */
function smtp_send(array $cfg, string $to, string $subject, string $body, array $attach = []): array
{
    $log = '';

    $read = function ($conn) use (&$log) {
        $line = '';
        while ($chunk = fgets($conn, 512)) {
            $log .= '<< ' . $chunk;
            $line = $chunk;
            if ($chunk[3] === ' ') break; // last line of multi-line response
        }
        return $line;
    };

    $write = function ($conn, string $cmd) use (&$log) {
        $log .= '>> ' . $cmd;
        fwrite($conn, $cmd);
    };

    $code = fn(string $line) => (int)substr($line, 0, 3);

    try {
        $host = trim($cfg['smtp_host']);
        $port = (int)$cfg['smtp_port'];
        $ssl  = ($port === 465);

        $conn = @fsockopen(($ssl ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10);
        if (!$conn) {
            return ['ok' => false, 'log' => "Connect failed: $errstr ($errno)"];
        }
        stream_set_timeout($conn, 10);

        $line = $read($conn);
        if ($code($line) !== 220) throw new RuntimeException("Unexpected greeting: $line");

        $write($conn, "EHLO omsorg-connect\r\n");
        $capabilities = '';
        while ($chunk = fgets($conn, 512)) {
            $log .= '<< ' . $chunk;
            $capabilities .= $chunk;
            if ($chunk[3] === ' ') break;
        }
        if ($code($capabilities) !== 250) throw new RuntimeException("EHLO failed");

        if (!$ssl && str_contains($capabilities, 'STARTTLS')) {
            $write($conn, "STARTTLS\r\n");
            $line = $read($conn);
            if ($code($line) !== 220) throw new RuntimeException("STARTTLS failed: $line");
            if (!stream_socket_enable_crypto($conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                throw new RuntimeException("TLS handshake failed");
            }
            $write($conn, "EHLO omsorg-connect\r\n");
            while ($chunk = fgets($conn, 512)) {
                $log .= '<< ' . $chunk;
                if ($chunk[3] === ' ') break;
            }
        }

        $write($conn, "AUTH LOGIN\r\n");
        $line = $read($conn);
        if ($code($line) !== 334) throw new RuntimeException("AUTH LOGIN failed: $line");

        $write($conn, base64_encode($cfg['smtp_user']) . "\r\n");
        $line = $read($conn);
        if ($code($line) !== 334) throw new RuntimeException("Username rejected: $line");

        $write($conn, base64_encode($cfg['smtp_password']) . "\r\n");
        $line = $read($conn);
        if ($code($line) !== 235) throw new RuntimeException("Password rejected: $line");

        $write($conn, "MAIL FROM:<{$cfg['mail_from']}>\r\n");
        $line = $read($conn);
        if ($code($line) !== 250) throw new RuntimeException("MAIL FROM failed: $line");

        $write($conn, "RCPT TO:<$to>\r\n");
        $line = $read($conn);
        if ($code($line) !== 250) throw new RuntimeException("RCPT TO failed: $line");

        $write($conn, "DATA\r\n");
        $line = $read($conn);
        if ($code($line) !== 354) throw new RuntimeException("DATA failed: $line");

        $enc_subject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
        $boundary    = 'omsorg_' . md5(uniqid((string)mt_rand(), true));

        $headers  = "From: OMSORG Connect <{$cfg['mail_from']}>\r\n";
        $headers .= "To: $to\r\n";
        $headers .= "Subject: $enc_subject\r\n";
        $headers .= "MIME-Version: 1.0\r\n";

        if ($attach) {
            $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
            $msg  = $headers . "\r\n";
            $msg .= "--$boundary\r\n";
            $msg .= "Content-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n";
            $msg .= $body . "\r\n\r\n";
            $safe_name  = preg_replace('/[^A-Za-z0-9._-]/', '_', $attach['name']);
            $file_data  = chunk_split(base64_encode(file_get_contents($attach['path'])));
            $msg .= "--$boundary\r\n";
            $msg .= "Content-Type: {$attach['mime']}; name=\"$safe_name\"\r\n";
            $msg .= "Content-Transfer-Encoding: base64\r\n";
            $msg .= "Content-Disposition: attachment; filename=\"$safe_name\"\r\n\r\n";
            $msg .= $file_data . "\r\n";
            $msg .= "--$boundary--";
        } else {
            $headers .= "Content-Type: text/plain; charset=UTF-8\r\n";
            $msg = $headers . "\r\n" . $body;
        }

        // Dot-stuffing: lines starting with '.' must be doubled
        $msg = str_replace("\n.", "\n..", $msg);
        $write($conn, $msg . "\r\n.\r\n");
        $line = $read($conn);
        if ($code($line) !== 250) throw new RuntimeException("Message rejected: $line");

        $write($conn, "QUIT\r\n");
        $read($conn);
        fclose($conn);

        return ['ok' => true, 'log' => $log];

    } catch (RuntimeException $e) {
        if (isset($conn) && is_resource($conn)) fclose($conn);
        return ['ok' => false, 'log' => $log . "\nError: " . $e->getMessage()];
    }
}
