<?php

declare(strict_types=1);

/**
 * FATE 系統信件：優先 Brevo API，否則 PHP mail()（mail() 回 true 僅表示主機收下，不保證送達）。
 * 環境變數：
 * - FATE_BREVO_API_KEY：Brevo v3 transactional（與 SMTP 區塊發信）
 * - FATE_MAIL_FROM：寄件人信箱（預設 noreply@localhost）
 * - FATE_MAIL_FROM_NAME：寄件名稱（選填）
 */

function fate_mail_from_address(): string
{
    if (!function_exists('fate_mail_resolved_sender')) {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_mail_settings.php';
    }
    $resolved = fate_mail_resolved_sender();

    return $resolved['mail_from'];
}

function fate_mail_from_label(): string
{
    if (!function_exists('fate_mail_resolved_sender')) {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_mail_settings.php';
    }

    return fate_mail_resolved_sender()['mail_from_name'];
}

/**
 * @param array{subject:string,to:string,plaintext:string,html?:string} $params
 */
function fate_mail_send_transactional(array $params): array
{
    $to = trim((string) ($params['to'] ?? ''));
    $subject = trim((string) ($params['subject'] ?? ''));
    $plain = (string) ($params['plaintext'] ?? '');
    $html = isset($params['html']) ? (string) $params['html'] : '';

    if ($to === '' || !filter_var($to, FILTER_VALIDATE_EMAIL)) {
        return ['ok' => false, 'detail' => '收件信箱無效'];
    }
    if ($subject === '') {
        return ['ok' => false, 'detail' => '主旨為空'];
    }

    if (!function_exists('fate_mail_settings_sanitize_from_email')) {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_mail_settings.php';
    }
    $from = isset($params['from_email']) && is_string($params['from_email'])
        ? fate_mail_settings_sanitize_from_email($params['from_email'])
        : fate_mail_from_address();
    if ($from === '') {
        return ['ok' => false, 'detail' => '請設定寄件人 Email（後台「Email 驗證」→ 系統發信，或環境變數 FATE_MAIL_FROM）'];
    }
    $senderName = isset($params['from_name']) && is_string($params['from_name'])
        ? fate_mail_settings_sanitize_from_name($params['from_name'])
        : fate_mail_from_label();
    if ($senderName === '') {
        $senderName = fate_mail_from_label();
    }

    if (!function_exists('fate_mail_effective_transport')) {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_mail_settings.php';
    }
    require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_api_keys.php';

    $transport = isset($params['transport']) && is_string($params['transport'])
        ? fate_mail_settings_sanitize_transport($params['transport'])
        : fate_mail_effective_transport();
    $brevoKey = fate_api_key('brevo_email');

    // 明確指定管道
    if ($transport === 'brevo') {
        if ($brevoKey === '') {
            return ['ok' => false, 'detail' => '已選 Brevo 發信，但未設定 API 金鑰（後台「網站與模版」或環境變數）'];
        }

        return fate_mail_via_brevo($brevoKey, $from, $senderName, $to, $subject, $plain, $html);
    }
    if ($transport === 'php_mail') {
        return fate_mail_via_php_mail($from, $senderName, $to, $subject, $plain, $html);
    }

    // auto：Brevo > PHP mail()
    if ($brevoKey !== '') {
        return fate_mail_via_brevo($brevoKey, $from, $senderName, $to, $subject, $plain, $html);
    }

    return fate_mail_via_php_mail($from, $senderName, $to, $subject, $plain, $html);
}

/**
 * PHP mail()：多數環境回傳 true 只代表交給本機 MTA，無法確認是否送達收件匣。
 *
 * @return array{ok:bool, detail:string, delivery_unverified?:bool}
 */
function fate_mail_is_windows(): bool
{
    return defined('PHP_OS_FAMILY') && PHP_OS_FAMILY === 'Windows';
}

/** Sendmail 用 -f；勿 escapeshellarg（PHP 手冊：-f&lt;email&gt; 不加引號）。Windows 忽略第 5 參數。 */
function fate_mail_php_mail_f_flag(string $from): string
{
    if (fate_mail_is_windows() || !filter_var($from, FILTER_VALIDATE_EMAIL)) {
        return '';
    }

    return '-f' . $from;
}

function fate_mail_php_mail_prepare_ini(string $from): void
{
    if (!filter_var($from, FILTER_VALIDATE_EMAIL)) {
        return;
    }
    if (fate_mail_is_windows()) {
        @ini_set('sendmail_from', $from);
    }
}

function fate_mail_php_mail_sendmail_binary(): string
{
    $path = trim((string) (ini_get('sendmail_path') ?: ''));
    if ($path === '') {
        return '';
    }
    $parts = preg_split('/\s+/', $path);

    return is_array($parts) && isset($parts[0]) ? trim($parts[0]) : '';
}

/**
 * 安全檢查檔案是否存在（共享主機 open_basedir 限制時不噴 Warning）。
 *
 * @return bool|null true/false 可判定；null 表示路徑不在 open_basedir 允許範圍內、無法檢查
 */
function fate_mail_safe_is_file(string $path): ?bool
{
    if (!function_exists('fate_path_safe_is_file')) {
        require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_path_safe.php';
    }

    return fate_path_safe_is_file($path);
}

function fate_mail_is_function_disabled(string $name): bool
{
    $disabled = strtolower(trim((string) (ini_get('disable_functions') ?: '')));
    if ($disabled === '') {
        return false;
    }
    foreach (preg_split('/\s*,\s*/', $disabled) as $fn) {
        if ($fn === strtolower($name)) {
            return true;
        }
    }

    return false;
}

/**
 * @return array{
 *   platform:string,
 *   sendmail_path:string,
 *   sendmail_binary:string,
 *   sendmail_binary_exists:bool,
 *   mail_disabled_in_ini:bool,
 *   hint:string
 * }
 */
function fate_mail_php_mail_diagnostic(): array
{
    $path = trim((string) (ini_get('sendmail_path') ?: ''));
    $bin = fate_mail_php_mail_sendmail_binary();
    $binCheck = $bin !== '' ? fate_mail_safe_is_file($bin) : false;
    $binExists = $binCheck === true;
    $mailOff = fate_mail_is_function_disabled('mail');

    $platform = fate_mail_is_windows() ? 'windows' : 'linux';

    return [
        'platform' => $platform,
        'sendmail_path' => $path,
        'sendmail_binary' => $bin,
        'sendmail_binary_exists' => $binExists,
        'sendmail_check_blocked' => $binCheck === null,
        'mail_disabled_in_ini' => $mailOff,
        'hint' => fate_mail_php_mail_environment_hint(),
    ];
}

/** 供後台／除錯：說明此 PHP 環境 mail() 為何容易回 false */
function fate_mail_php_mail_environment_hint(): string
{
    if (fate_mail_is_function_disabled('mail')) {
        return 'php.ini 的 disable_functions 已停用 mail()，請於 PHP 設定移除 mail，或改用 Brevo API。';
    }

    if (fate_mail_is_windows()) {
        $smtp = trim((string) (ini_get('SMTP') ?: ''));
        $port = trim((string) (ini_get('smtp_port') ?: '25'));
        $fromIni = trim((string) (ini_get('sendmail_from') ?: ''));
        if ($smtp === '' || strcasecmp($smtp, 'localhost') === 0) {
            return 'Windows／XAMPP：php.ini 的 [mail function] 預設 SMTP=localhost 且常未啟動，mail() 會直接回 false。請改設真實 SMTP，或改用 Brevo。'
                . ($fromIni !== '' ? ' sendmail_from=' . $fromIni : '');
        }

        return 'Windows：SMTP=' . $smtp . ':' . $port
            . ($fromIni !== '' ? '；sendmail_from=' . $fromIni : '（建議設定 sendmail_from 與寄件人一致）');
    }

    $path = trim((string) (ini_get('sendmail_path') ?: ''));
    $bin = fate_mail_php_mail_sendmail_binary();

    if ($path === '') {
        return 'Linux：php.ini 未設定 sendmail_path（無 sendmail/postfix 時 mail() 常回 false），請安裝 MTA 或改用 Brevo。';
    }
    if ($bin !== '') {
        $binCheck = fate_mail_safe_is_file($bin);
        if ($binCheck === null) {
            return 'sendmail_path=' . (strlen($path) > 80 ? substr($path, 0, 80) . '…' : $path)
                . '（主機 open_basedir 限制，無法檢查 sendmail 是否存在；若 mail() 失敗請改用 SMTP／Brevo）。';
        }
        if ($binCheck === false) {
            return 'sendmail_path 指向的程式不存在：' . $bin . '，請修正 php.ini 或改用 Brevo。';
        }
    }

    return 'sendmail_path=' . (strlen($path) > 100 ? substr($path, 0, 100) . '…' : $path);
}

function fate_mail_via_php_mail(
    string $from,
    string $senderName,
    string $to,
    string $subject,
    string $plain,
    string $html = ''
): array {
    fate_mail_php_mail_prepare_ini($from);

    $headers = ['MIME-Version: 1.0', 'From: ' . fate_mail_encode_mailbox($senderName, $from)];
    $body = $plain;
    if ($html !== '') {
        $boundary = 'fate_' . bin2hex(random_bytes(8));
        $headers[] = 'Content-Type: multipart/alternative; boundary="' . $boundary . '"';
        $body = "--{$boundary}\r\n"
            . "Content-Type: text/plain; charset=UTF-8\r\n\r\n"
            . $plain . "\r\n\r\n"
            . "--{$boundary}\r\n"
            . "Content-Type: text/html; charset=UTF-8\r\n\r\n"
            . $html . "\r\n\r\n"
            . "--{$boundary}--";
    } else {
        $headers[] = 'Content-Type: text/plain; charset=UTF-8';
    }

    $headerStr = implode("\r\n", $headers);
    $encodedSubject = fate_mail_encode_mime_subject($subject);
    $fFlag = fate_mail_php_mail_f_flag($from);

    $accepted = fate_mail_invoke_mail($to, $encodedSubject, $body, $headerStr, $fFlag);
    if ($accepted !== true && $fFlag !== '') {
        $accepted = fate_mail_invoke_mail($to, $encodedSubject, $body, $headerStr, '');
    }

    if ($accepted !== true) {
        $diag = fate_mail_php_mail_diagnostic();

        return [
            'ok' => false,
            'detail' => 'mail() 回傳 false（' . $diag['hint'] . '）',
            'mail_diagnostic' => $diag['hint'],
            'mail_diagnostic_detail' => $diag,
        ];
    }

    return [
        'ok' => true,
        'detail' => 'mail() 已交予主機寄信程式',
        'delivery_unverified' => true,
        'transport' => 'php_mail',
        'from_email' => $from,
        'to_email' => $to,
        'delivery_note' => '僅表示主機 mail 程式收下，無法確認是否送達。未收到請查郵件伺服器日誌、垃圾信，或改設 Brevo API。',
    ];
}

function fate_mail_invoke_mail(string $to, string $subject, string $body, string $headers, string $additionalParams): bool
{
    if ($additionalParams !== '') {
        return @mail($to, $subject, $body, $headers, $additionalParams);
    }

    return @mail($to, $subject, $body, $headers);
}

function fate_mail_encode_mailbox(string $name, string $email): string
{
    return sprintf('=?UTF-8?B?%s?= <%s>', base64_encode($name), $email);
}

function fate_mail_encode_mime_subject(string $subject): string
{
    return '=?UTF-8?B?' . base64_encode($subject) . '?=';
}

/**
 * @return array{ok:bool,detail:string}
 */
function fate_mail_via_brevo(string $apiKey, string $fromEmail, string $senderName, string $to, string $subject, string $plain, string $html): array
{
    $payload = [
        'sender' => ['name' => $senderName, 'email' => $fromEmail],
        'to' => [['email' => $to]],
        'subject' => $subject,
        'textContent' => $plain,
    ];
    if ($html !== '') {
        $payload['htmlContent'] = $html;
    }

    $ch = curl_init('https://api.brevo.com/v3/smtp/email');
    if ($ch === false) {
        return ['ok' => false, 'detail' => 'curl init failed'];
    }
    $bodyJson = json_encode($payload, JSON_UNESCAPED_UNICODE);
    if ($bodyJson === false) {
        return ['ok' => false, 'detail' => 'json encode failed'];
    }

    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'accept: application/json',
            'api-key: ' . $apiKey,
            'content-type: application/json',
        ],
        CURLOPT_POSTFIELDS => $bodyJson,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 25,
        CURLOPT_CONNECTTIMEOUT => 10,
    ]);
    $raw = curl_exec($ch);
    $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($raw === false || $code < 200 || $code >= 300) {
        $hint = $raw !== false && $raw !== '' ? substr(trim((string) $raw), 0, 280) : 'HTTP ' . $code;

        return ['ok' => false, 'detail' => 'Brevo API 錯誤：' . $hint];
    }

    $messageId = '';
    if ($raw !== false && $raw !== '') {
        $j = json_decode((string) $raw, true);
        if (is_array($j) && isset($j['messageId']) && is_string($j['messageId'])) {
            $messageId = trim($j['messageId']);
        }
    }

    $detail = $messageId !== '' ? 'brevo（messageId: ' . $messageId . '）' : 'brevo';

    return [
        'ok' => true,
        'detail' => $detail,
        'transport' => 'brevo',
        'message_id' => $messageId,
        'from_email' => $fromEmail,
        'to_email' => $to,
        'delivery_note' => 'Brevo 已接受寄信請求。若收件匣沒有，請至 Brevo 後台 Transactional → Logs 用 messageId 查狀態，並檢查垃圾信／促銷分類。',
    ];
}
