<?php
/**
 * Clase simple para envío de emails vía SMTP
 * Compatible con Hotmail/Outlook, Gmail y otros servidores SMTP
 */

class SMTPMailer {
    private $smtp_host;
    private $smtp_port;
    private $smtp_username;
    private $smtp_password;
    private $smtp_encryption; // 'tls' o 'ssl'
    private $timeout = 30;
    private $socket = null;
    private $lastError = ''; // Almacenar último error detallado
    
    public function __construct($host, $port, $username, $password, $encryption = 'tls') {
        $this->smtp_host = $host;
        $this->smtp_port = $port;
        $this->smtp_username = $username;
        $this->smtp_password = $password;
        $this->smtp_encryption = $encryption;
    }
    
    /**
     * Obtener el último error detallado
     */
    public function getLastError() {
        return $this->lastError;
    }
    
    /**
     * Enviar email vía SMTP
     */
    public function send($to, $subject, $message, $fromEmail, $fromName, $htmlMessage = null) {
        $this->lastError = ''; // Limpiar error anterior
        try {
            // Conectar al servidor SMTP
            if (!$this->connect()) {
                return false;
            }
            
            // Autenticación
            if (!$this->authenticate()) {
                $this->disconnect();
                return false;
            }
            
            // Enviar email
            $result = $this->sendEmail($to, $subject, $message, $fromEmail, $fromName, $htmlMessage);
            
            $this->disconnect();
            return $result;
            
        } catch (Exception $e) {
            $this->lastError = "Excepción: " . $e->getMessage();
            error_log("Error SMTP: " . $e->getMessage());
            $this->disconnect();
            return false;
        }
    }
    
    /**
     * Conectar al servidor SMTP
     */
    private function connect() {
        $host = $this->smtp_host;
        $connectionString = $host;
        if ($this->smtp_encryption === 'ssl') {
            $connectionString = 'ssl://' . $host;
        }
        
        $this->socket = @fsockopen($connectionString, $this->smtp_port, $errno, $errstr, $this->timeout);
        
        if (!$this->socket) {
            $this->lastError = "No se pudo conectar a $connectionString:$this->smtp_port - Error: $errstr (Código: $errno)";
            error_log("Error conectando a SMTP: $errstr ($errno)");
            return false;
        }
        
        // Leer respuesta inicial
        $response = $this->getResponse();
        if (substr($response, 0, 3) !== '220') {
            $this->lastError = "Respuesta SMTP inesperada al conectar: $response";
            error_log("Respuesta SMTP inesperada: $response");
            return false;
        }
        
        // Iniciar TLS si es necesario
        if ($this->smtp_encryption === 'tls') {
            $this->sendCommand('EHLO ' . $this->smtp_host);
            $this->getResponse(); // Leer respuesta EHLO
            
            $this->sendCommand('STARTTLS');
            $response = $this->getResponse();
            if (substr($response, 0, 3) !== '220') {
                $this->lastError = "Error iniciando TLS: $response";
                error_log("Error iniciando TLS: $response");
                return false;
            }
            
            if (!stream_socket_enable_crypto($this->socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
                $this->lastError = "Error habilitando cifrado TLS";
                error_log("Error habilitando TLS");
                return false;
            }
            
            // Enviar EHLO nuevamente después de TLS
            $this->sendCommand('EHLO ' . $this->smtp_host);
            $this->getResponse();
        }
        
        return true;
    }
    
    /**
     * Autenticarse en el servidor SMTP
     * Intenta AUTH LOGIN primero, luego AUTH PLAIN si falla
     */
    private function authenticate() {
        // Si ya se envió EHLO en connect() (para TLS), no enviarlo de nuevo
        if ($this->smtp_encryption !== 'tls') {
            $this->sendCommand('EHLO ' . $this->smtp_host);
            $this->getResponse();
        }
        
        // Intentar AUTH LOGIN primero
        $this->sendCommand('AUTH LOGIN');
        $response = $this->getResponse();
        
        if (substr($response, 0, 3) === '334') {
            // AUTH LOGIN aceptado, continuar
            // Usuario
            $this->sendCommand(base64_encode($this->smtp_username));
            $response = $this->getResponse();
            if (substr($response, 0, 3) !== '334') {
                $this->lastError = "Error enviando usuario (AUTH LOGIN): $response";
                error_log("Error enviando usuario (AUTH LOGIN): $response");
                // Intentar AUTH PLAIN como alternativa
                return $this->tryAuthPlain();
            }
            
            // Contraseña
            $this->sendCommand(base64_encode($this->smtp_password));
            $response = $this->getResponse();
            if (substr($response, 0, 3) === '235') {
                return true; // Autenticación exitosa
            } else {
                $this->lastError = "Error en autenticación AUTH LOGIN (credenciales incorrectas?): $response";
                error_log("Error en autenticación AUTH LOGIN: $response");
                // Intentar AUTH PLAIN como alternativa
                return $this->tryAuthPlain();
            }
        } else {
            // AUTH LOGIN no soportado, intentar AUTH PLAIN
            $this->lastError = "AUTH LOGIN no soportado: $response. Intentando AUTH PLAIN...";
            error_log("AUTH LOGIN no soportado: $response");
            return $this->tryAuthPlain();
        }
    }
    
    /**
     * Intentar autenticación AUTH PLAIN
     */
    private function tryAuthPlain() {
        // AUTH PLAIN: formato es base64("\0username\0password")
        $authString = base64_encode("\0" . $this->smtp_username . "\0" . $this->smtp_password);
        
        $this->sendCommand('AUTH PLAIN ' . $authString);
        $response = $this->getResponse();
        
        if (substr($response, 0, 3) === '235') {
            return true; // Autenticación exitosa
        } else {
            // Ambos métodos fallaron
            $this->lastError = "Error en autenticación AUTH PLAIN: $response\n";
            $this->lastError .= "Se intentaron ambos métodos (AUTH LOGIN y AUTH PLAIN) y ambos fallaron.\n";
            $this->lastError .= "Posibles causas:\n";
            $this->lastError .= "1. Usuario o contraseña incorrectos\n";
            $this->lastError .= "2. El servidor SMTP requiere un método de autenticación diferente\n";
            $this->lastError .= "3. La cuenta de email está bloqueada o deshabilitada\n";
            $this->lastError .= "4. El servidor SMTP no permite autenticación desde esta IP\n";
            $this->lastError .= "\nVerifica las credenciales en config/email-config.php";
            error_log("Error en autenticación AUTH PLAIN: $response");
            return false;
        }
    }
    
    /**
     * Enviar el email
     */
    private function sendEmail($to, $subject, $message, $fromEmail, $fromName, $htmlMessage = null) {
        // MAIL FROM
        $this->sendCommand('MAIL FROM:<' . $fromEmail . '>');
        $response = $this->getResponse();
        if (substr($response, 0, 3) !== '250') {
            $this->lastError = "Error en MAIL FROM: $response";
            error_log("Error en MAIL FROM: $response");
            return false;
        }
        
        // RCPT TO
        $this->sendCommand('RCPT TO:<' . $to . '>');
        $response = $this->getResponse();
        if (substr($response, 0, 3) !== '250') {
            $this->lastError = "Error en RCPT TO: $response";
            error_log("Error en RCPT TO: $response");
            return false;
        }
        
        // DATA
        $this->sendCommand('DATA');
        $response = $this->getResponse();
        if (substr($response, 0, 3) !== '354') {
            $this->lastError = "Error en DATA: $response";
            error_log("Error en DATA: $response");
            return false;
        }
        
        // Construir mensaje
        $emailMessage = $this->buildMessage($to, $subject, $message, $fromEmail, $fromName, $htmlMessage);
        
        // Enviar mensaje
        fwrite($this->socket, $emailMessage . "\r\n.\r\n");
        $response = $this->getResponse();
        
        if (substr($response, 0, 3) !== '250') {
            // Detectar tipo específico de error
            $responseCode = substr($response, 0, 3);
            $responseText = trim($response);
            
            if ($responseCode === '550') {
                // Error 550: Rechazado por el servidor
                if (stripos($responseText, 'SPAM') !== false || stripos($responseText, 'spam') !== false) {
                    $this->lastError = "Error 550 - Mensaje clasificado como SPAM: $response\n\n";
                    $this->lastError .= "El servidor SMTP rechazó el mensaje porque lo considera spam.\n\n";
                    $this->lastError .= "Posibles causas:\n";
                    $this->lastError .= "1. El servidor tiene restricciones para enviar a dominios externos (como hotmail.com, gmail.com)\n";
                    $this->lastError .= "2. Falta configuración SPF/DKIM/DMARC en el dominio\n";
                    $this->lastError .= "3. El contenido del mensaje está siendo marcado como spam\n";
                    $this->lastError .= "4. El servidor tiene políticas anti-spam muy estrictas\n\n";
                    $this->lastError .= "Soluciones:\n";
                    $this->lastError .= "- Contacta al hosting para verificar restricciones de envío\n";
                    $this->lastError .= "- Solicita que configuren SPF/DKIM/DMARC para tu dominio\n";
                    $this->lastError .= "- Verifica si hay restricciones para enviar a dominios externos\n";
                } else {
                    $this->lastError = "Error 550 - Mensaje rechazado: $response";
                }
            } else {
                $this->lastError = "Error enviando mensaje (Código $responseCode): $response";
            }
            
            error_log("Error enviando mensaje: $response");
            return false;
        }
        
        return true;
    }
    
    /**
     * Construir el mensaje del email
     */
    private function buildMessage($to, $subject, $textMessage, $fromEmail, $fromName, $htmlMessage = null) {
        $boundary = md5(uniqid(time()));
        
        $message = "From: " . $fromName . " <" . $fromEmail . ">\r\n";
        $message .= "To: <" . $to . ">\r\n";
        $message .= "Subject: =?UTF-8?B?" . base64_encode($subject) . "?=\r\n";
        $message .= "MIME-Version: 1.0\r\n";
        
        if ($htmlMessage) {
            $message .= "Content-Type: multipart/alternative; boundary=\"$boundary\"\r\n";
            $message .= "\r\n";
            $message .= "--$boundary\r\n";
            $message .= "Content-Type: text/plain; charset=UTF-8\r\n";
            $message .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
            $message .= $textMessage . "\r\n\r\n";
            $message .= "--$boundary\r\n";
            $message .= "Content-Type: text/html; charset=UTF-8\r\n";
            $message .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
            $message .= $htmlMessage . "\r\n\r\n";
            $message .= "--$boundary--\r\n";
        } else {
            $message .= "Content-Type: text/plain; charset=UTF-8\r\n";
            $message .= "Content-Transfer-Encoding: 8bit\r\n\r\n";
            $message .= $textMessage . "\r\n";
        }
        
        return $message;
    }
    
    /**
     * Enviar comando al servidor SMTP
     */
    private function sendCommand($command) {
        fwrite($this->socket, $command . "\r\n");
    }
    
    /**
     * Obtener respuesta del servidor
     */
    private function getResponse() {
        $response = '';
        while ($line = fgets($this->socket, 515)) {
            $response .= $line;
            if (substr($line, 3, 1) === ' ') {
                break;
            }
        }
        return trim($response);
    }
    
    /**
     * Desconectar del servidor SMTP
     */
    private function disconnect() {
        if ($this->socket) {
            $this->sendCommand('QUIT');
            $this->getResponse();
            fclose($this->socket);
            $this->socket = null;
        }
    }
}
?>

