<?php

namespace App\Utils;

use App\Config\Database;

class SimpleMailer {
    /**
     * Send an email with a PDF attachment using credentials stored in smtp_settings.
     *
     * @param string $toEmails Comma-separated list of destination emails
     * @param string $subject Subject line
     * @param string $htmlBody HTML body content
     * @param string $pdfContent PDF binary content
     * @param string $pdfFilename Name of the attached PDF file
     * @throws \Exception
     */
    public static function send(string $toEmails, string $subject, string $htmlBody, string $pdfContent, string $pdfFilename) {
        $db = Database::getInstance()->getConnection();
        
        // Fetch SMTP configuration
        $stmt = $db->query("SELECT * FROM smtp_settings LIMIT 1");
        $settings = $stmt->fetch();
        if (!$settings) {
            throw new \Exception("SMTP Settings not found in database.");
        }
        
        $host = $settings['smtp_host'];
        $port = (int)$settings['smtp_port'];
        $username = $settings['smtp_username'];
        $password = $settings['smtp_password'];
        $fromName = $settings['from_name'];
        $fromEmail = !empty($settings['from_email']) ? $settings['from_email'] : $username;
        
        // Split and sanitize recipient email list
        $recipients = array_filter(array_map('trim', explode(',', $toEmails)));
        if (empty($recipients)) {
            throw new \Exception("No valid recipient email addresses provided.");
        }
        
        // SMTPS context (ignore self-signed certs for compatibility/reliability)
        $context = stream_context_create([
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false,
                'allow_self_signed' => true,
            ]
        ]);
        
        // Establish TCP connection over SSL
        $socket = @stream_socket_client("ssl://{$host}:{$port}", $errno, $errstr, 15, STREAM_CLIENT_CONNECT, $context);
        if (!$socket) {
            throw new \Exception("Could not connect to SMTP server: {$errstr} ({$errno})");
        }
        
        try {
            // SMTP handshake
            self::readResponse($socket, '220');
            
            fwrite($socket, "EHLO localhost\r\n");
            self::readResponse($socket, '250');
            
            fwrite($socket, "AUTH LOGIN\r\n");
            self::readResponse($socket, '334');
            
            fwrite($socket, base64_encode($username) . "\r\n");
            self::readResponse($socket, '334');
            
            fwrite($socket, base64_encode($password) . "\r\n");
            self::readResponse($socket, '235');
            
            // SMTP Transactions
            fwrite($socket, "MAIL FROM:<{$fromEmail}>\r\n");
            self::readResponse($socket, '250');
            
            foreach ($recipients as $recipient) {
                fwrite($socket, "RCPT TO:<{$recipient}>\r\n");
                self::readResponse($socket, '250');
            }
            
            fwrite($socket, "DATA\r\n");
            self::readResponse($socket, '354');
            
            // Construct MIME message
            $boundary = "----=_Part_" . md5(uniqid(time()));
            
            $headers = [];
            $headers[] = "From: =?UTF-8?B?" . base64_encode($fromName) . "?= <{$fromEmail}>";
            $headers[] = "To: " . implode(', ', $recipients);
            $headers[] = "Subject: =?UTF-8?B?" . base64_encode($subject) . "?=";
            $headers[] = "MIME-Version: 1.0";
            $headers[] = "Content-Type: multipart/mixed; boundary=\"{$boundary}\"";
            $headers[] = "Date: " . date('r');
            $headers[] = "Message-ID: <" . md5(uniqid(time())) . "@" . gethostname() . ">";
            
            $body = "";
            
            // HTML body chunk
            $body .= "--{$boundary}\r\n";
            $body .= "Content-Type: text/html; charset=utf-8\r\n";
            $body .= "Content-Transfer-Encoding: base64\r\n\r\n";
            $body .= chunk_split(base64_encode($htmlBody)) . "\r\n";
            
            // PDF attachment chunk
            $body .= "--{$boundary}\r\n";
            $body .= "Content-Type: application/pdf; name=\"{$pdfFilename}\"\r\n";
            $body .= "Content-Disposition: attachment; filename=\"{$pdfFilename}\"\r\n";
            $body .= "Content-Transfer-Encoding: base64\r\n\r\n";
            $body .= chunk_split(base64_encode($pdfContent)) . "\r\n";
            
            $body .= "--{$boundary}--";
            
            $mailData = implode("\r\n", $headers) . "\r\n\r\n" . $body;
            
            // Send MIME payload
            fwrite($socket, $mailData . "\r\n.\r\n");
            self::readResponse($socket, '250');
            
            // Graceful exit
            fwrite($socket, "QUIT\r\n");
            self::readResponse($socket, '221');
        } finally {
            fclose($socket);
        }
    }
    
    /**
     * Helper method to read from socket and assert expected status code.
     *
     * @param resource $socket
     * @param string $expectedCode
     * @return string
     * @throws \Exception
     */
    private static function readResponse($socket, string $expectedCode): string {
        $response = "";
        while ($line = fgets($socket, 512)) {
            $response .= $line;
            // Check for multiline response separator (space vs hyphen)
            if (strlen($line) >= 4 && substr($line, 3, 1) === ' ') {
                break;
            }
        }
        $code = substr($response, 0, 3);
        if ($code !== $expectedCode) {
            throw new \Exception("SMTP Protocol Error: Expected '{$expectedCode}', but server returned: '" . trim($response) . "'");
        }
        return $response;
    }
}
