<?php
// ─────────────────────────────────────────────
// includes/mailer.php
//
// Schlanker SMTP-Client für mail.come2canada.life:465 (SSL).
// Eine zentrale Funktion: c2c_send_mail() — protokolliert in mail_log.
//
// Erwartet diese Konstanten in secrets.php:
//   define('SMTP_HOST', 'mail.come2canada.life');
//   define('SMTP_PORT', 465);
//   define('SMTP_USER', 'mail@come2canada.life');
//   define('SMTP_PASS', 'XXX');
//
// Plus aus config.php:
//   MAIL_FROM, MAIL_FROM_NAME, MAIL_NOTIFY
// ─────────────────────────────────────────────

require_once __DIR__ . '/db.php';

/**
 * Sendet eine Mail über SMTP und loggt das Ergebnis in mail_log.
 *
 * @param string  $to        Empfänger-E-Mail
 * @param string  $subject   Betreff
 * @param string  $template  Template-Name ohne .html (in /templates/mails/)
 * @param array   $vars      Variablen, die im Template ersetzt werden ({{name}} etc.)
 * @param ?string $toName    Empfänger-Name (optional)
 * @param ?int    $clientId  Klient-ID für mail_log (optional)
 * @return array  ['ok' => bool, 'mail_id' => int, 'error' => ?string]
 */
function c2c_send_mail(
    string $to,
    string $subject,
    string $template,
    array $vars = [],
    ?string $toName = null,
    ?int $clientId = null
): array {
    $db = C2CDatabase::get();

    // Log-Eintrag mit Status 'queued' anlegen
    $stmt = $db->prepare("
        INSERT INTO mail_log (client_id, to_email, to_name, subject, template, status)
        VALUES (?, ?, ?, ?, ?, 'queued')
    ");
    $stmt->execute([$clientId, $to, $toName, $subject, $template]);
    $mailId = (int)$db->lastInsertId();

    try {
        // Template laden
        $body = c2c_load_template($template, $vars);

        // SMTP-Versand
        $smtp = new C2CSmtpClient(SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS);
        $smtp->send(
            MAIL_FROM,
            MAIL_FROM_NAME,
            $to,
            $toName ?: $to,
            $subject,
            $body
        );

        $db->prepare("UPDATE mail_log SET status='sent', sent_at=NOW() WHERE id=?")
           ->execute([$mailId]);

        return ['ok' => true, 'mail_id' => $mailId];

    } catch (Throwable $e) {
        $db->prepare("UPDATE mail_log SET status='failed', error=? WHERE id=?")
           ->execute([$e->getMessage(), $mailId]);
        error_log("c2c_send_mail Fehler an $to: " . $e->getMessage());
        return ['ok' => false, 'mail_id' => $mailId, 'error' => $e->getMessage()];
    }
}

/**
 * Lädt ein HTML-Template aus /c2c/templates/mails/ und ersetzt {{var}}-Platzhalter.
 */
function c2c_load_template(string $name, array $vars): string {
    $path = __DIR__ . '/../templates/mails/' . basename($name) . '.html';
    if (!file_exists($path)) {
        throw new RuntimeException("Mail-Template nicht gefunden: $name");
    }

    $html = file_get_contents($path);

    foreach ($vars as $key => $value) {
        $html = str_replace('{{' . $key . '}}', (string)$value, $html);
    }

    return $html;
}

/**
 * Schlanker SMTP-Client. Spricht SSL/465 mit Auth-Login.
 * Bewusst klein gehalten — keine externe Library.
 */
class C2CSmtpClient {
    private string $host;
    private int    $port;
    private string $user;
    private string $pass;
    private        $socket = null;
    private int    $timeout = 30;
    private bool   $debug = false;

    public function __construct(string $host, int $port, string $user, string $pass) {
        $this->host = $host;
        $this->port = $port;
        $this->user = $user;
        $this->pass = $pass;
    }

    public function send(
        string $fromAddr, string $fromName,
        string $toAddr,   string $toName,
        string $subject,  string $htmlBody
    ): void {
        $this->connect();
        try {
            $this->ehlo();
            $this->authenticate();
            $this->sendMail($fromAddr, $fromName, $toAddr, $toName, $subject, $htmlBody);
            $this->command('QUIT', 221);
        } finally {
            $this->disconnect();
        }
    }

    private function connect(): void {
        $address = ($this->port === 465 ? 'ssl://' : '') . $this->host . ':' . $this->port;
        $errno = 0;
        $errstr = '';

        $this->socket = @stream_socket_client(
            $address,
            $errno,
            $errstr,
            $this->timeout,
            STREAM_CLIENT_CONNECT
        );

        if (!$this->socket) {
            throw new RuntimeException("SMTP-Verbindung fehlgeschlagen ($errno): $errstr");
        }

        stream_set_timeout($this->socket, $this->timeout);
        $this->expectCode(220, $this->readResponse());
    }

    private function ehlo(): void {
        $this->command('EHLO ' . ($_SERVER['SERVER_NAME'] ?? 'come2canada.life'), 250);
    }

    private function authenticate(): void {
        $this->command('AUTH LOGIN', 334);
        $this->command(base64_encode($this->user), 334);
        $this->command(base64_encode($this->pass), 235);
    }

    private function sendMail(
        string $fromAddr, string $fromName,
        string $toAddr,   string $toName,
        string $subject,  string $htmlBody
    ): void {
        $this->command("MAIL FROM:<$fromAddr>", 250);
        $this->command("RCPT TO:<$toAddr>",     250);
        $this->command("DATA", 354);

        $headers = $this->buildHeaders($fromAddr, $fromName, $toAddr, $toName, $subject);
        $payload = $headers . "\r\n\r\n" . $this->encodeBody($htmlBody) . "\r\n.";

        $this->write($payload . "\r\n");
        $this->expectCode(250, $this->readResponse());
    }

    private function buildHeaders(
        string $fromAddr, string $fromName,
        string $toAddr,   string $toName,
        string $subject
    ): string {
        $messageId = '<' . bin2hex(random_bytes(12)) . '@' . parse_url('http://' . $this->host, PHP_URL_HOST) . '>';
        $date      = date('r');

        $encodedSubject  = '=?UTF-8?B?' . base64_encode($subject) . '?=';
        $encodedFromName = '=?UTF-8?B?' . base64_encode($fromName) . '?=';
        $encodedToName   = '=?UTF-8?B?' . base64_encode($toName)   . '?=';

        return implode("\r\n", [
            "Date: $date",
            "Message-ID: $messageId",
            "From: $encodedFromName <$fromAddr>",
            "To: $encodedToName <$toAddr>",
            "Subject: $encodedSubject",
            "MIME-Version: 1.0",
            "Content-Type: text/html; charset=UTF-8",
            "Content-Transfer-Encoding: base64",
            "X-Mailer: c2c-mailer/1.0",
        ]);
    }

    private function encodeBody(string $body): string {
        // Body als base64 in 76-Zeichen-Zeilen (RFC-konform)
        return chunk_split(base64_encode($body), 76, "\r\n");
    }

    private function command(string $cmd, int $expectCode): void {
        $this->write($cmd . "\r\n");
        $response = $this->readResponse();
        $this->expectCode($expectCode, $response);
    }

    private function write(string $data): void {
        if ($this->debug) error_log("SMTP > " . trim($data));
        fwrite($this->socket, $data);
    }

    private function readResponse(): string {
        $response = '';
        while ($line = fgets($this->socket, 1024)) {
            $response .= $line;
            // Nach SMTP-Spec: Letzte Zeile hat Format "NNN " (Space), Zwischenzeilen "NNN-"
            if (isset($line[3]) && $line[3] === ' ') break;
        }
        if ($this->debug) error_log("SMTP < " . trim($response));
        return $response;
    }

    private function expectCode(int $expected, string $response): void {
        $code = (int)substr($response, 0, 3);
        if ($code !== $expected) {
            throw new RuntimeException("SMTP unerwartete Antwort: $response (erwartet: $expected)");
        }
    }

    private function disconnect(): void {
        if ($this->socket) {
            @fclose($this->socket);
            $this->socket = null;
        }
    }
}
