<?php
declare(strict_types=1);

require_once __DIR__ . '/config.php';

function golder_smtp_env_config(): array
{
    return [
        'host' => trim(golder_env('GOLDER_SMTP_HOST', '')),
        'port' => (int)golder_env('GOLDER_SMTP_PORT', '587'),
        'user' => trim(golder_env('GOLDER_SMTP_USER', '')),
        'pass' => (string)golder_env('GOLDER_SMTP_PASS', ''),
        'from_email' => trim(golder_env('GOLDER_SMTP_FROM_EMAIL', '')),
        'from_name' => trim(golder_env('GOLDER_SMTP_FROM_NAME', 'Golder')),
        'secure' => strtolower(trim(golder_env('GOLDER_SMTP_SECURE', 'tls'))),
        'timeout' => max(3, (int)golder_env('GOLDER_SMTP_TIMEOUT', '15')),
    ];
}

function golder_smtp_read_line($fp): string
{
    $line = '';
    while (!feof($fp)) {
        $chunk = fgets($fp, 512);
        if ($chunk === false) {
            break;
        }
        $line .= $chunk;
        if (strlen($chunk) < 4) {
            break;
        }
        // SMTP multi-line responses have "<code>-", final line has "<code> ".
        if (preg_match('/^[0-9]{3}\s/', $chunk) === 1) {
            break;
        }
    }
    return trim($line);
}

function golder_smtp_expect($fp, array $allowedCodes, string &$lastResponse): bool
{
    $lastResponse = golder_smtp_read_line($fp);
    $code = (int)substr($lastResponse, 0, 3);
    return in_array($code, $allowedCodes, true);
}

function golder_smtp_cmd($fp, string $cmd, array $allowedCodes, string &$lastResponse): bool
{
    fwrite($fp, $cmd . "\r\n");
    return golder_smtp_expect($fp, $allowedCodes, $lastResponse);
}

function golder_smtp_message(string $fromEmail, string $fromName, string $toEmail, string $subject, string $textBody, string $htmlBody = ''): string
{
    $encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
    $headers = [];
    $headers[] = 'From: ' . $fromName . ' <' . $fromEmail . '>';
    $headers[] = 'To: <' . $toEmail . '>';
    $headers[] = 'Subject: ' . $encodedSubject;
    $headers[] = 'MIME-Version: 1.0';
    $headers[] = 'Date: ' . gmdate('D, d M Y H:i:s') . ' +0000';

    if (trim($htmlBody) !== '') {
        $boundary = 'golder_' . bin2hex(random_bytes(8));
        $headers[] = 'Content-Type: multipart/alternative; boundary="' . $boundary . '"';
        $parts = [];
        $parts[] = '--' . $boundary;
        $parts[] = 'Content-Type: text/plain; charset=UTF-8';
        $parts[] = 'Content-Transfer-Encoding: 8bit';
        $parts[] = '';
        $parts[] = $textBody;
        $parts[] = '--' . $boundary;
        $parts[] = 'Content-Type: text/html; charset=UTF-8';
        $parts[] = 'Content-Transfer-Encoding: 8bit';
        $parts[] = '';
        $parts[] = $htmlBody;
        $parts[] = '--' . $boundary . '--';
        $parts[] = '';
        return implode("\r\n", array_merge($headers, [''], $parts));
    }

    $headers[] = 'Content-Type: text/plain; charset=UTF-8';
    $headers[] = 'Content-Transfer-Encoding: 8bit';
    return implode("\r\n", array_merge($headers, ['', $textBody]));
}

function golder_send_smtp_mail(string $toEmail, string $subject, string $textBody, string $htmlBody = ''): array
{
    $cfg = golder_smtp_env_config();
    if ($cfg['host'] === '' || $cfg['from_email'] === '') {
        return ['ok' => false, 'message' => 'SMTP env is not configured.'];
    }
    if (filter_var($toEmail, FILTER_VALIDATE_EMAIL) === false) {
        return ['ok' => false, 'message' => 'recipient email is invalid.'];
    }

    $transport = ($cfg['secure'] === 'ssl') ? 'ssl://' : '';
    $target = $transport . $cfg['host'] . ':' . (int)$cfg['port'];
    $fp = @stream_socket_client($target, $errno, $errstr, (float)$cfg['timeout'], STREAM_CLIENT_CONNECT);
    if (!$fp) {
        return ['ok' => false, 'message' => 'SMTP connect failed: ' . $errstr . ' (' . $errno . ')'];
    }
    stream_set_timeout($fp, (int)$cfg['timeout']);

    $last = '';
    try {
        if (!golder_smtp_expect($fp, [220], $last)) {
            return ['ok' => false, 'message' => 'SMTP greeting failed: ' . $last];
        }

        if (!golder_smtp_cmd($fp, 'EHLO golder.local', [250], $last)) {
            return ['ok' => false, 'message' => 'SMTP EHLO failed: ' . $last];
        }

        if ($cfg['secure'] === 'tls') {
            if (!golder_smtp_cmd($fp, 'STARTTLS', [220], $last)) {
                return ['ok' => false, 'message' => 'SMTP STARTTLS failed: ' . $last];
            }
            if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                return ['ok' => false, 'message' => 'SMTP TLS crypto negotiation failed.'];
            }
            if (!golder_smtp_cmd($fp, 'EHLO golder.local', [250], $last)) {
                return ['ok' => false, 'message' => 'SMTP EHLO after TLS failed: ' . $last];
            }
        }

        if ($cfg['user'] !== '') {
            if (!golder_smtp_cmd($fp, 'AUTH LOGIN', [334], $last)) {
                return ['ok' => false, 'message' => 'SMTP AUTH LOGIN failed: ' . $last];
            }
            if (!golder_smtp_cmd($fp, base64_encode($cfg['user']), [334], $last)) {
                return ['ok' => false, 'message' => 'SMTP AUTH username failed: ' . $last];
            }
            if (!golder_smtp_cmd($fp, base64_encode($cfg['pass']), [235], $last)) {
                return ['ok' => false, 'message' => 'SMTP AUTH password failed: ' . $last];
            }
        }

        if (!golder_smtp_cmd($fp, 'MAIL FROM:<' . $cfg['from_email'] . '>', [250], $last)) {
            return ['ok' => false, 'message' => 'SMTP MAIL FROM failed: ' . $last];
        }
        if (!golder_smtp_cmd($fp, 'RCPT TO:<' . $toEmail . '>', [250, 251], $last)) {
            return ['ok' => false, 'message' => 'SMTP RCPT TO failed: ' . $last];
        }
        if (!golder_smtp_cmd($fp, 'DATA', [354], $last)) {
            return ['ok' => false, 'message' => 'SMTP DATA failed: ' . $last];
        }

        $payload = golder_smtp_message(
            (string)$cfg['from_email'],
            (string)$cfg['from_name'],
            $toEmail,
            $subject,
            $textBody,
            $htmlBody
        );
        fwrite($fp, $payload . "\r\n.\r\n");
        if (!golder_smtp_expect($fp, [250], $last)) {
            return ['ok' => false, 'message' => 'SMTP message send failed: ' . $last];
        }

        golder_smtp_cmd($fp, 'QUIT', [221, 250], $last);
        fclose($fp);
        return ['ok' => true, 'message' => 'sent'];
    } catch (Throwable $e) {
        @fclose($fp);
        return ['ok' => false, 'message' => 'SMTP send exception: ' . $e->getMessage()];
    }
}


