<?php
/**
 * 邮件发送类
 * 支持QQ邮箱SMTP发送
 */
namespace lib;

class EmailSender {
    private $smtpServer;
    private $smtpPort;
    private $smtpUser;
    private $smtpPass;
    private $smtpSecure;
    private $fromEmail;
    private $fromName;
    private $isEnabled;
    private $error = '';
    private $socket = null;
    
    /**
     * 构造函数
     */
    public function __construct($config = null) {
        if ($config === null) {
            $config = $this->getConfigFromDB();
        }
        
        if ($config) {
            $this->smtpServer = $config['smtp_server'] ?? 'smtp.qq.com';
            $this->smtpPort = intval($config['smtp_port'] ?? 587);
            $this->smtpUser = $config['smtp_user'] ?? '';
            $this->smtpPass = $config['smtp_pass'] ?? '';
            $this->smtpSecure = $config['smtp_secure'] ?? 'tls';
            $this->fromEmail = $config['from_email'] ?? $this->smtpUser;
            $this->fromName = $config['from_name'] ?? '彩虹外链网盘';
            $this->isEnabled = intval($config['is_enabled'] ?? 0);
        }
    }
    
    /**
     * 从数据库获取配置
     */
    private function getConfigFromDB() {
        global $DB;
        if (!isset($DB)) {
            return null;
        }
        
        try {
            $config = $DB->getRow("SELECT * FROM pre_email_config WHERE id=1 LIMIT 1");
            return $config;
        } catch (\Exception $e) {
            return null;
        }
    }
    
    /**
     * 检查邮件功能是否已配置并启用
     */
    public function isReady() {
        if (!$this->isEnabled) {
            $this->error = '邮件功能未启用';
            return false;
        }
        if (empty($this->smtpUser) || empty($this->smtpPass)) {
            $this->error = '邮件服务器未配置';
            return false;
        }
        return true;
    }
    
    /**
     * 发送邮件
     * @param string $to 收件人邮箱
     * @param string $subject 邮件主题
     * @param string $body 邮件内容（HTML格式）
     * @param string $altBody 纯文本内容（可选）
     * @return bool
     */
    public function send($to, $subject, $body, $altBody = '') {
        if (!$this->isReady()) {
            return false;
        }
        
        if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {
            $this->error = '收件人邮箱格式不正确';
            return false;
        }
        
        // 生成邮件内容
        $message = $this->buildMessage($to, $subject, $body, $altBody);
        
        // 使用mail()函数发送（如果可用）
        if (function_exists('mail') && ini_get('sendmail_path')) {
            return $this->sendViaMail($to, $subject, $body, $altBody);
        }
        
        // 使用SMTP发送
        return $this->sendViaSmtp($to, $message);
    }
    
    /**
     * 使用mail()函数发送
     */
    private function sendViaMail($to, $subject, $body, $altBody) {
        $headers = "From: {$this->fromName} <{$this->fromEmail}>\r\n";
        $headers .= "Reply-To: {$this->fromEmail}\r\n";
        $headers .= "MIME-Version: 1.0\r\n";
        $headers .= "Content-Type: text/html; charset=UTF-8\r\n";
        
        $result = mail($to, $subject, $body, $headers);
        if (!$result) {
            $this->error = 'mail()函数发送失败';
        }
        return $result;
    }
    
    /**
     * 使用SMTP发送
     */
    private function sendViaSmtp($to, $message) {
        $this->socket = @fsockopen(
            $this->smtpSecure === 'ssl' ? 'ssl://' . $this->smtpServer : $this->smtpServer,
            $this->smtpPort,
            $errno,
            $errstr,
            30
        );
        
        if (!$this->socket) {
            $this->error = "无法连接到SMTP服务器: {$errstr} ({$errno})";
            return false;
        }
        
        // 读取服务器响应
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '220') {
            $this->error = 'SMTP服务器连接失败: ' . $response;
            $this->close();
            return false;
        }
        
        // EHLO/HELO
        $this->sendCommand('EHLO ' . gethostname());
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '250') {
            $this->sendCommand('HELO ' . gethostname());
            $response = $this->getResponse();
            if (substr($response, 0, 3) != '250') {
                $this->error = 'EHLO/HELO失败: ' . $response;
                $this->close();
                return false;
            }
        }
        
        // STARTTLS (如果需要)
        if ($this->smtpSecure === 'tls' && $this->smtpPort == 587) {
            $this->sendCommand('STARTTLS');
            $response = $this->getResponse();
            if (substr($response, 0, 3) != '220') {
                $this->error = 'STARTTLS失败: ' . $response;
                $this->close();
                return false;
            }
            
            // 启用TLS加密
            if (!stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                $this->error = 'TLS加密启用失败';
                $this->close();
                return false;
            }
            
            // 重新EHLO
            $this->sendCommand('EHLO ' . gethostname());
            $response = $this->getResponse();
            if (substr($response, 0, 3) != '250') {
                $this->error = 'EHLO (after TLS)失败: ' . $response;
                $this->close();
                return false;
            }
        }
        
        // AUTH LOGIN
        $this->sendCommand('AUTH LOGIN');
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '334') {
            $this->error = 'AUTH LOGIN失败: ' . $response;
            $this->close();
            return false;
        }
        
        // 发送用户名
        $this->sendCommand(base64_encode($this->smtpUser));
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '334') {
            $this->error = '用户名验证失败: ' . $response;
            $this->close();
            return false;
        }
        
        // 发送密码
        $this->sendCommand(base64_encode($this->smtpPass));
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '235') {
            $this->error = '密码验证失败: ' . $response;
            $this->close();
            return false;
        }
        
        // MAIL FROM
        $this->sendCommand('MAIL FROM:<' . $this->fromEmail . '>');
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '250') {
            $this->error = 'MAIL FROM失败: ' . $response;
            $this->close();
            return false;
        }
        
        // RCPT TO
        $this->sendCommand('RCPT TO:<' . $to . '>');
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '250' && substr($response, 0, 3) != '251') {
            $this->error = 'RCPT TO失败: ' . $response;
            $this->close();
            return false;
        }
        
        // DATA
        $this->sendCommand('DATA');
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '354') {
            $this->error = 'DATA命令失败: ' . $response;
            $this->close();
            return false;
        }
        
        // 发送邮件内容
        $this->sendCommand($message . "\r\n.");
        $response = $this->getResponse();
        if (substr($response, 0, 3) != '250') {
            $this->error = '邮件发送失败: ' . $response;
            $this->close();
            return false;
        }
        
        // QUIT
        $this->sendCommand('QUIT');
        $this->close();
        
        return true;
    }
    
    /**
     * 构建邮件内容
     */
    private function buildMessage($to, $subject, $body, $altBody) {
        $boundary = md5(uniqid() . time());
        
        $message = "MIME-Version: 1.0\r\n";
        $message .= "Content-Type: multipart/alternative; boundary=\"{$boundary}\"\r\n";
        $message .= "From: =?UTF-8?B?" . base64_encode($this->fromName) . "?= <{$this->fromEmail}>\r\n";
        $message .= "To: {$to}\r\n";
        $message .= "Subject: =?UTF-8?B?" . base64_encode($subject) . "?=\r\n";
        $message .= "Date: " . date('r') . "\r\n";
        $message .= "\r\n";
        
        // 纯文本部分
        if (!empty($altBody)) {
            $message .= "--{$boundary}\r\n";
            $message .= "Content-Type: text/plain; charset=UTF-8\r\n";
            $message .= "Content-Transfer-Encoding: base64\r\n";
            $message .= "\r\n";
            $message .= chunk_split(base64_encode($altBody)) . "\r\n";
        }
        
        // HTML部分
        $message .= "--{$boundary}\r\n";
        $message .= "Content-Type: text/html; charset=UTF-8\r\n";
        $message .= "Content-Transfer-Encoding: base64\r\n";
        $message .= "\r\n";
        $message .= chunk_split(base64_encode($body)) . "\r\n";
        
        $message .= "--{$boundary}--\r\n";
        
        return $message;
    }
    
    /**
     * 发送命令
     */
    private function sendCommand($command) {
        if ($this->socket) {
            fwrite($this->socket, $command . "\r\n");
        }
    }
    
    /**
     * 获取响应
     */
    private function getResponse() {
        $response = '';
        if ($this->socket) {
            while ($line = fgets($this->socket, 515)) {
                $response .= $line;
                if (substr($line, 3, 1) == ' ') {
                    break;
                }
            }
        }
        return $response;
    }
    
    /**
     * 关闭连接
     */
    private function close() {
        if ($this->socket) {
            fclose($this->socket);
            $this->socket = null;
        }
    }
    
    /**
     * 获取错误信息
     */
    public function getError() {
        return $this->error;
    }
    
    /**
     * 生成验证码邮件模板
     */
    public function getVerifyCodeTemplate($code, $type) {
        $typeText = [
            'register' => '注册账号',
            'resetpwd' => '找回密码',
            'bind' => '绑定邮箱',
            'unbind' => '解绑邮箱'
        ];
        
        $typeName = $typeText[$type] ?? '验证操作';
        
        $html = <<<HTML
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>邮箱验证码</title>
    <style>
        body { font-family: 'Microsoft YaHei', Arial, sans-serif; background-color: #f5f5f5; margin: 0; padding: 20px; }
        .container { max-width: 600px; margin: 0 auto; background: #ffffff; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .header { background: linear-gradient(135deg, #0f766e 0%, #14b8a6 100%); padding: 30px; text-align: center; }
        .header h1 { color: #ffffff; margin: 0; font-size: 24px; }
        .content { padding: 40px 30px; }
        .greeting { font-size: 16px; color: #333; margin-bottom: 20px; }
        .info { font-size: 14px; color: #666; margin-bottom: 30px; line-height: 1.6; }
        .code-box { background: #f8f9fa; border: 2px dashed #14b8a6; border-radius: 8px; padding: 20px; text-align: center; margin: 30px 0; }
        .code { font-size: 32px; font-weight: bold; color: #0f766e; letter-spacing: 8px; }
        .code-label { font-size: 14px; color: #888; margin-bottom: 10px; }
        .warning { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin-top: 30px; font-size: 13px; color: #856404; }
        .footer { background: #f8f9fa; padding: 20px; text-align: center; font-size: 12px; color: #888; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>{$this->fromName}</h1>
        </div>
        <div class="content">
            <div class="greeting">您好！</div>
            <div class="info">
                您正在进行<strong>{$typeName}</strong>操作，请输入以下验证码完成验证。
                <br><br>
                该验证码将于 <strong>10分钟</strong> 后过期，请尽快使用。
            </div>
            <div class="code-box">
                <div class="code-label">您的验证码</div>
                <div class="code">{$code}</div>
            </div>
            <div class="warning">
                <strong>温馨提示：</strong><br>
                1. 验证码仅用于{$typeName}，请勿泄露给他人<br>
                2. 如非本人操作，请忽略此邮件<br>
                3. 验证码有效期为10分钟
            </div>
        </div>
        <div class="footer">
            此邮件由系统自动发送，请勿回复<br>
            &copy; {$this->fromName} 版权所有
        </div>
    </div>
</body>
</html>
HTML;
        
        $altBody = "您好！\n\n";
        $altBody .= "您正在进行{$typeName}操作，请输入以下验证码完成验证。\n\n";
        $altBody .= "验证码：{$code}\n\n";
        $altBody .= "该验证码将于10分钟后过期，请尽快使用。\n\n";
        $altBody .= "如非本人操作，请忽略此邮件。\n";
        $altBody .= "此邮件由系统自动发送，请勿回复。";
        
        return ['html' => $html, 'text' => $altBody];
    }
    
    /**
     * 发送验证码邮件
     */
    public function sendVerifyCode($to, $code, $type) {
        $template = $this->getVerifyCodeTemplate($code, $type);
        $typeText = [
            'register' => '注册验证',
            'resetpwd' => '密码重置',
            'bind' => '邮箱绑定',
            'unbind' => '邮箱解绑'
        ];
        $subject = $typeText[$type] ?? '邮箱验证';
        
        return $this->send($to, $subject . ' - ' . $this->fromName, $template['html'], $template['text']);
    }
}
