<?php
/**
 * UltraGuard Pro - Mail Manager
 *
 * A fluent, chainable mail builder for sending HTML and plain-text emails
 * with license-aware footers, template support, and pre-built notifications.
 *
 * @package    UltraguardPro\core
 * @author     UltraGuard Pro Team
 * @version    2.0.0
 * @since      1.0.0
 */

namespace UltraguardPro\core;

use UltraguardPro\support\LicenseInfo;

// Prevent direct access.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/**
 * =============================================================================
 * QUICK START EXAMPLES
 * =============================================================================
 *
 * // 1. BASIC HTML EMAIL
 * MailManager::make()
 *     ->to('admin@example.com', 'Admin')
 *     ->subject('Scan Complete')
 *     ->html('<h1>No threats found</h1><p>Your site is clean.</p>')
 *     ->send();
 *
 * // 2. PLAIN TEXT EMAIL
 * MailManager::make()
 *     ->to('user@example.com')
 *     ->subject('Alert')
 *     ->text('Intrusion detected and blocked.')
 *     ->send();
 *
 * // 3. WITH CC, BCC, AND ATTACHMENTS
 * MailManager::make()
 *     ->to('primary@example.com')
 *     ->addTo('secondary@example.com', 'Secondary')
 *     ->cc('manager@example.com')
 *     ->bcc('audit@example.com')
 *     ->subject('Monthly Report')
 *     ->template('monthly-report', ['data' => $stats])
 *     ->attach('/path/to/report.pdf', 'report.pdf')
 *     ->replyTo('reports@example.com')
 *     ->send();
 *
 * // 4. USING TEMPLATES
 * MailManager::make()
 *     ->to('team@example.com')
 *     ->subject('Weekly Stats')
 *     ->template('weekly-stats', [
 *         'visitors' => 1234,
 *         'threats' => 5,
 *         'uptime' => '99.9%'
 *     ])
 *     ->send();
 *
 * // 5. PRE-BUILT NOTIFICATIONS
 * MailManager::scanComplete('admin@example.com', [
 *     'threats' => 2,
 *     'scanned' => 1500,
 *     'duration' => '2.5 minutes'
 * ]);
 *
 * MailManager::intrusionAlert('security@example.com', [
 *     'ip' => '192.168.1.100',
 *     'type' => 'brute-force',
 *     'url' => '/wp-login.php',
 *     'timestamp' => current_time('mysql')
 * ]);
 *
 * MailManager::statusUpdate(
 *     'admin@example.com',
 *     'Firewall Updated',
 *     'New rules have been applied successfully.',
 *     ['rules_added' => 15, 'rules_updated' => 8]
 * );
 *
 * // 6. PROMOTIONAL EMAIL (Free plan users)
 * MailManager::promotion('freeuser@example.com', [
 *     'name' => 'John',
 *     'headline' => 'Get Real-Time Protection',
 *     'cta_label' => 'Upgrade Now →'
 * ]);
 *
 * // 7. WITH CUSTOM FROM ADDRESS
 * MailManager::make()
 *     ->from('noreply@ultraguard.net', 'UltraGuard Security')
 *     ->to('user@example.com')
 *     ->subject('Important Update')
 *     ->wrappedText('Your security settings have been updated.', 'Settings Changed')
 *     ->send();
 *
 * // 8. CHAIN MULTIPLE EMAILS
 * $mailer = MailManager::make();
 *
 * $mailer->to('first@example.com')->subject('First')->html('<p>Hi</p>')->send();
 * $mailer->reset()->to('second@example.com')->subject('Second')->html('<p>Hello</p>')->send();
 *
 * // 9. WITH ERROR HANDLING
 * $result = MailManager::make()
 *     ->to('invalid-email')
 *     ->subject('Test')
 *     ->text('Body')
 *     ->send();
 *
 * if (!$result) {
 *     $error = MailManager::make()->getLastError();
 *     error_log('Mail failed: ' . $error->get_error_message());
 * }
 *
 * // 10. USING RECIPIENT HELPER
 * MailManager::make()
 *     ->to(MailManager::recipient('john@example.com', 'John Doe'))
 *     ->addTo(MailManager::recipient('jane@example.com', 'Jane Doe'))
 *     ->subject('Hello')
 *     ->html('<p>Welcome</p>')
 *     ->send();
 *
 * // 11. WITH CUSTOM HEADERS
 * MailManager::make()
 *     ->to('user@example.com')
 *     ->subject('Priority Message')
 *     ->html('<p>Urgent</p>')
 *     ->header('X-Priority', '1')
 *     ->header('X-MSMail-Priority', 'High')
 *     ->send();
 *
 * // 12. BATCH SENDING
 * $users = ['user1@ex.com', 'user2@ex.com', 'user3@ex.com'];
 * foreach ($users as $user) {
 *     MailManager::make()
 *         ->to($user)
 *         ->subject('Newsletter')
 *         ->template('newsletter', ['user' => $user])
 *         ->sendAndReset(); // Sends and resets for next iteration
 * }
 */

/**
 * Class MailManager
 *
 * Fluent email builder with license-aware footers and pre-built notifications.
 */
class MailManager {

    // =========================================================================
    // CONSTANTS
    // =========================================================================

    /** @var string HTML content type */
    public const TYPE_HTML = 'text/html';

    /** @var string Plain text content type */
    public const TYPE_TEXT = 'text/plain';

    /** @var string Default charset */
    public const CHARSET = 'UTF-8';

    /** @var int Free plan definition delay in days */
    public const FREE_DELAY_DAYS = 15;

    /** @var int Maximum attachment size (10MB) */
    public const MAX_ATTACHMENT_SIZE = 10485760;

    /** @var array Allowed attachment MIME types */
    public const ALLOWED_ATTACHMENT_TYPES = [
        'application/pdf',
        'application/zip',
        'text/plain',
        'text/csv',
        'application/json',
        'image/png',
        'image/jpeg',
        'image/gif',
    ];

    // =========================================================================
    // PROPERTIES - Instance state
    // =========================================================================

    /** @var array Primary recipients */
    private array $to = [];

    /** @var array CC recipients */
    private array $cc = [];

    /** @var array BCC recipients */
    private array $bcc = [];

    /** @var string Email subject */
    private string $subject = '';

    /** @var string Email body */
    private string $body = '';

    /** @var string Content type */
    private string $content_type = self::TYPE_HTML;

    /** @var string Character set */
    private string $charset = self::CHARSET;

    /** @var array From address and name */
    private array $from = [];

    /** @var array Reply-To address and name */
    private array $reply_to = [];

    /** @var array Attachments */
    private array $attachments = [];

    /** @var array Additional headers */
    private array $extra_headers = [];

    /** @var \WP_Error|null Last error */
    private ?\WP_Error $last_error = null;

    /** @var bool Debug mode */
    private bool $debug_mode = false;

    /** @var array Template variables cache */
    private array $template_vars = [];

    /** @var bool Whether to auto-wrap HTML content */
    private bool $auto_wrap = true;

    /** @var string Email format (html/text/both) */
    private string $format = 'html';

    /** @var string Plain text version (for multipart emails) */
    private string $plain_text = '';

    // =========================================================================
    // STATIC PROPERTIES
    // =========================================================================

    /** @var array Default headers applied to all emails */
    private static array $global_headers = [];

    /** @var callable|null Global error handler */
    private static $error_handler = null;

    /** @var array Statistics for sent emails */
    private static array $stats = [
        'sent' => 0,
        'failed' => 0,
        'last_sent' => null,
    ];

    // =========================================================================
    // CONSTRUCTOR & FACTORY
    // =========================================================================

    /**
     * Constructor.
     */
    public function __construct() {
        $this->debug_mode = defined('WP_DEBUG') && WP_DEBUG;
        $this->apply_plugin_defaults();
    }

    /**
     * Create a fresh MailManager instance.
     *
     * @return static
     */
    public static function make(): self {
        return new static();
    }

    // =========================================================================
    // RECIPIENT HELPERS
    // =========================================================================

    /**
     * Build a recipient array.
     *
     * @param string $address Email address
     * @param string $name Optional display name
     * @return array
     * @throws \InvalidArgumentException
     */
    public static function recipient(string $address, string $name = ''): array {
        $address = sanitize_email($address);
        if (!is_email($address)) {
            throw new \InvalidArgumentException(esc_html( "Invalid email address: {$address}" ));
        }

        return [
            'address' => $address,
            'name' => sanitize_text_field($name),
        ];
    }

    // =========================================================================
    // FLUENT SETTERS - Recipients
    // =========================================================================

    /**
     * Set primary recipients.
     *
     * @param string|array $to
     * @param string $name
     * @return static
     */
    public function to($to, string $name = ''): self {
        $this->to = $this->parse_recipients($to, $name);
        return $this;
    }

    /**
     * Append To recipients.
     *
     * @param string|array $to
     * @param string $name
     * @return static
     */
    public function addTo($to, string $name = ''): self {
        $this->to = array_merge($this->to, $this->parse_recipients($to, $name));
        return $this;
    }

    /**
     * Set CC recipients.
     *
     * @param string|array $cc
     * @param string $name
     * @return static
     */
    public function cc($cc, string $name = ''): self {
        $this->cc = $this->parse_recipients($cc, $name);
        return $this;
    }

    /**
     * Append CC recipients.
     *
     * @param string|array $cc
     * @param string $name
     * @return static
     */
    public function addCc($cc, string $name = ''): self {
        $this->cc = array_merge($this->cc, $this->parse_recipients($cc, $name));
        return $this;
    }

    /**
     * Set BCC recipients.
     *
     * @param string|array $bcc
     * @param string $name
     * @return static
     */
    public function bcc($bcc, string $name = ''): self {
        $this->bcc = $this->parse_recipients($bcc, $name);
        return $this;
    }

    /**
     * Append BCC recipients.
     *
     * @param string|array $bcc
     * @param string $name
     * @return static
     */
    public function addBcc($bcc, string $name = ''): self {
        $this->bcc = array_merge($this->bcc, $this->parse_recipients($bcc, $name));
        return $this;
    }

    // =========================================================================
    // FLUENT SETTERS - Sender Information
    // =========================================================================

    /**
     * Set From address.
     *
     * @param string $address
     * @param string $name
     * @return static
     * @throws \InvalidArgumentException
     */
    public function from(string $address, string $name = ''): self {
        $address = sanitize_email($address);
        if (!is_email($address)) {
            throw new \InvalidArgumentException(esc_html( "Invalid from email address: {$address}" ));
        }

        $this->from = [
            'address' => $address,
            'name' => sanitize_text_field($name),
        ];
        return $this;
    }

    /**
     * Set Reply-To address.
     *
     * @param string $address
     * @param string $name
     * @return static
     * @throws \InvalidArgumentException
     */
    public function replyTo(string $address, string $name = ''): self {
        $address = sanitize_email($address);
        if (!is_email($address)) {
            throw new \InvalidArgumentException(esc_html( "Invalid reply-to email address: {$address}" ));
        }

        $this->reply_to = [
            'address' => $address,
            'name' => sanitize_text_field($name),
        ];
        return $this;
    }

    // =========================================================================
    // FLUENT SETTERS - Content
    // =========================================================================

    /**
     * Set email subject.
     *
     * @param string $subject
     * @return static
     */
    public function subject(string $subject): self {
        $this->subject = sanitize_text_field($subject);
        return $this;
    }

    /**
     * Set HTML body.
     *
     * @param string $html
     * @param bool $auto_wrap Whether to auto-wrap in template
     * @return static
     */
    public function html(string $html, bool $auto_wrap = true): self {
        $this->body = $html;
        $this->content_type = self::TYPE_HTML;
        $this->auto_wrap = $auto_wrap;
        $this->format = 'html';
        return $this;
    }

    /**
     * Set plain text body.
     *
     * @param string $text
     * @return static
     */
    public function text(string $text): self {
        $this->body = $text;
        $this->content_type = self::TYPE_TEXT;
        $this->format = 'text';
        return $this;
    }

    /**
     * Set both HTML and plain text versions (multipart).
     *
     * @param string $html
     * @param string $plain
     * @return static
     */
    public function multipart(string $html, string $plain): self {
        $this->body = $html;
        $this->plain_text = $plain;
        $this->content_type = self::TYPE_HTML;
        $this->format = 'both';
        return $this;
    }

    /**
     * Load template and render.
     *
     * @param string $template Template slug
     * @param array $vars Template variables
     * @return static
     */
    public function template(string $template, array $vars = []): self {
        $path = $this->resolve_template_path($template);

        if (!$path) {
            $this->log_error("Template not found: {$template}");
            return $this;
        }

        $this->template_vars = $vars;
        $this->body = $this->render_template($path, $vars);
        $this->content_type = self::TYPE_HTML;
        $this->format = 'html';

        return $this;
    }

    /**
     * Wrap text in HTML template.
     *
     * @param string $text
     * @param string $heading
     * @return static
     */
    public function wrappedText(string $text, string $heading = ''): self {
        return $this->html(
            $this->apply_html_wrapper(
                nl2br(esc_html($text)),
                $heading
            )
        );
    }

    // =========================================================================
    // FLUENT SETTERS - Attachments
    // =========================================================================

    /**
     * Attach a file.
     *
     * @param string $path Absolute file path
     * @param string $filename Custom filename
     * @param string $mime_type MIME type
     * @return static
     * @throws \InvalidArgumentException
     */
    public function attach(string $path, string $filename = '', string $mime_type = ''): self {
        if (!file_exists($path)) {
            throw new \InvalidArgumentException(esc_html( "Attachment not found: {$path}" ));
        }

        if (filesize($path) > self::MAX_ATTACHMENT_SIZE) {
            throw new \InvalidArgumentException(esc_html( "Attachment too large (max 10MB): {$path}" ));
        }

        if ($mime_type && !in_array($mime_type, self::ALLOWED_ATTACHMENT_TYPES, true)) {
            throw new \InvalidArgumentException(esc_html( "Unsupported attachment type: {$mime_type}" ));
        }

        $this->attachments[] = [
            'path' => $path,
            'filename' => $filename ?: basename($path),
            'mime' => $mime_type ?: $this->get_mime_type($path),
        ];

        return $this;
    }

    /**
     * Attach multiple files.
     *
     * @param array $files Array of file paths or [path, filename, mime] arrays
     * @return static
     */
    public function attachMultiple(array $files): self {
        foreach ($files as $file) {
            if (is_string($file)) {
                $this->attach($file);
            } elseif (is_array($file) && isset($file[0])) {
                $this->attach(
                    $file[0],
                    $file[1] ?? '',
                    $file[2] ?? ''
                );
            }
        }
        return $this;
    }

    /**
     * Clear all attachments.
     *
     * @return static
     */
    public function clearAttachments(): self {
        $this->attachments = [];
        return $this;
    }

    // =========================================================================
    // FLUENT SETTERS - Headers & Configuration
    // =========================================================================

    /**
     * Add custom header.
     *
     * @param string $name
     * @param string $value
     * @return static
     */
    public function header(string $name, string $value): self {
        $this->extra_headers[sanitize_text_field($name)] = sanitize_text_field($value);
        return $this;
    }

    /**
     * Set content type.
     *
     * @param string $content_type
     * @return static
     */
    public function contentType(string $content_type): self {
        $this->content_type = $content_type;
        return $this;
    }

    /**
     * Set charset.
     *
     * @param string $charset
     * @return static
     */
    public function charset(string $charset): self {
        $this->charset = $charset;
        return $this;
    }

    /**
     * Enable/disable auto-wrapping.
     *
     * @param bool $wrap
     * @return static
     */
    public function autoWrap(bool $wrap = true): self {
        $this->auto_wrap = $wrap;
        return $this;
    }

    // =========================================================================
    // SENDING METHODS
    // =========================================================================

    /**
     * Send the email.
     *
     * @return bool
     */
    public function send(): bool {
        // Validate required fields
        if (!$this->validate()) {
            return false;
        }

        if (!$this->mail_transport_available()) {
            $this->last_error = new \WP_Error(
                'mail_transport_unavailable',
                __('Local mail transport is not configured on this server.', 'ultraguard-security-suite')
            );
            $this->update_stats(false);
            if ($this->debug_mode) {
                $this->log_debug(false);
            }
            return false;
        }

        // Prepare content
        $body = $this->prepare_body();
        $to = $this->build_address_list($this->to);
        $headers = $this->build_headers();
        $attachments = array_column($this->attachments, 'path');

        // Handle multipart if needed
        if ($this->format === 'both' && !empty($this->plain_text)) {
            add_filter('phpmailer_init', [$this, '_setup_multipart']);
        }

        // Set up filters
        $this->add_filters();

        // Send
        $result = wp_mail($to, $this->subject, $body, $headers, $attachments);

        // Clean up
        $this->remove_filters();
        if ($this->format === 'both') {
            remove_filter('phpmailer_init', [$this, '_setup_multipart']);
        }

        // Update stats
        $this->update_stats($result);

        // Log if debug mode
        if ($this->debug_mode) {
            $this->log_debug($result);
        }

        return $result;
    }

    /**
     * Basic transport preflight for local Windows/WAMP style installs.
     *
     * wp_mail() can exist while PHP has no usable backend configured, which
     * leads to noisy "Could not instantiate mail function" failures. Detect
     * the obvious no-transport cases before calling into PHPMailer.
     *
     * @return bool
     */
    private function mail_transport_available(): bool {
        if (!function_exists('wp_mail')) {
            return false;
        }

        $sendmail_path = trim((string) ini_get('sendmail_path'));
        $smtp_host = trim((string) ini_get('SMTP'));

        if (DIRECTORY_SEPARATOR === '\\') {
            return $smtp_host !== '';
        }

        return $sendmail_path !== '' || $smtp_host !== '';
    }

    /**
     * Send and reset for reuse.
     *
     * @return bool
     */
    public function sendAndReset(): bool {
        $result = $this->send();
        $this->reset();
        return $result;
    }

    /**
     * Send asynchronously (if WP_Async_Request available).
     *
     * @return bool
     */
    public function sendAsync(): bool {
        if (!class_exists('WP_Async_Request')) {
            return $this->send();
        }

        // Store email data for async processing
        $data = [
            'to' => $this->to,
            'subject' => $this->subject,
            'body' => $this->body,
            'headers' => $this->build_headers(),
            'attachments' => array_column($this->attachments, 'path'),
            'content_type' => $this->content_type,
            'charset' => $this->charset,
        ];

        CacheManager::get_instance()->set('ug_mail_async_' . uniqid(), $data, 'short');

        // Trigger async action
        do_action('ug_send_async_email', $data);

        return true;
    }

    // =========================================================================
    // PRE-BUILT NOTIFICATIONS
    // =========================================================================

    /**
     * Send scan complete notification.
     *
     * @param string $to_address
     * @param array $scan_data
     * @return bool
     */
    public static function scanComplete(string $to_address, array $scan_data): bool {
        $threats = (int)($scan_data['threats'] ?? 0);
        $scanned = (int)($scan_data['scanned'] ?? 0);
        $duration = (string)($scan_data['duration'] ?? 'N/A');
        $site = get_bloginfo('name');

        $status_label = $threats > 0
            ? sprintf('%d threat(s) found', $threats)
            : 'No threats found ✓';

        $subject = sprintf('[%s] Scan Complete — %s', $site, $status_label);

        $details = [
            'Files Scanned' => number_format($scanned),
            'Threats Found' => $threats,
            'Duration' => $duration,
            'Site' => $site,
        ];

        if (!empty($scan_data['threat_list'])) {
            $details['Threat Details'] = $scan_data['threat_list'];
        }

        $html = self::make()->build_notification_html(
            'Scan Complete',
            $status_label,
            $details,
            $threats > 0 ? 'warning' : 'success'
        );

        return self::make()
            ->to($to_address)
            ->subject($subject)
            ->html($html)
            ->send();
    }

    /**
     * Send intrusion alert.
     *
     * @param string $to_address
     * @param array $event_data
     * @return bool
     */
    public static function intrusionAlert(string $to_address, array $event_data): bool {
        $site = get_bloginfo('name');
        $severity = $event_data['severity'] ?? 'high';

        $severity_icons = [
            'critical' => '🔴',
            'high' => '⚠️',
            'medium' => '⚡',
            'low' => 'ℹ️',
        ];

        $icon = $severity_icons[$severity] ?? '⚠️';

        $subject = sprintf('[%s] %s Security Alert — Intrusion Detected', $site, $icon);

        $details = [
            'IP Address' => $event_data['ip'] ?? 'N/A',
            'Type' => $event_data['type'] ?? 'N/A',
            'Time' => $event_data['timestamp'] ?? current_time('mysql'),
            'URL' => $event_data['url'] ?? 'N/A',
            'User Agent' => $event_data['user_agent'] ?? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? 'N/A' ) ),
            'Site' => $site,
        ];

        if (!empty($event_data['additional_data'])) {
            $details = array_merge($details, $event_data['additional_data']);
        }

        $html = self::make()->build_notification_html(
            "{$icon} Intrusion Detected",
            'A suspicious activity was blocked on your site.',
            $details,
            'danger'
        );

        return self::make()
            ->to($to_address)
            ->subject($subject)
            ->html($html)
            ->send();
    }

    /**
     * Send status update.
     *
     * @param string $to_address
     * @param string $subject
     * @param string $message
     * @param array $details
     * @return bool
     */
    public static function statusUpdate(
        string $to_address,
        string $subject,
        string $message,
        array $details = []
    ): bool {
        $html = self::make()->build_notification_html(
            $subject,
            $message,
            $details,
            'info'
        );

        return self::make()
            ->to($to_address)
            ->subject($subject)
            ->html($html)
            ->send();
    }

    /**
     * Send promotional email.
     *
     * @param string $to_address
     * @param array $promo_data
     * @return bool
     */
    public static function promotion(string $to_address, array $promo_data = []): bool {
        if (class_exists(LicenseInfo::class) && LicenseInfo::instance()->isPro() && empty($promo_data['force'])) {
            return true;
        }

        $site = get_bloginfo('name');
        $subject = sprintf('[%s] 🚀 Upgrade to UltraGuard Pro — Real-Time Protection', $site);
        $html = self::make()->build_promotion_html($promo_data);

        return self::make()
            ->to($to_address)
            ->subject($subject)
            ->html($html)
            ->send();
    }

    /**
     * Send a branded UltraGuard notification email.
     *
     * @param array $args
     * @return bool
     */
    public static function notification(array $args): bool {
        $subject     = (string) ($args['subject'] ?? '');
        $title       = (string) ($args['title'] ?? $subject);
        $message     = (string) ($args['message'] ?? '');
        $details     = is_array($args['details'] ?? null) ? $args['details'] : [];
        $tone        = (string) ($args['tone'] ?? 'info');
        $cta_url     = esc_url_raw((string) ($args['cta_url'] ?? ''));
        $cta_label   = (string) ($args['cta_label'] ?? '');
        $footer_note = (string) ($args['footer_note'] ?? '');
        $to          = $args['to'] ?? [];
        $attachments = is_array($args['attachments'] ?? null) ? $args['attachments'] : [];
        $headers     = is_array($args['headers'] ?? null) ? $args['headers'] : [];

        if (empty($to) || '' === $subject || ('' === $message && empty($details))) {
            return false;
        }

        $mailer = self::make();
        $mailer->to($to)->subject($subject)->multipart(
            $mailer->build_notification_html($title, $message, $details, $tone, $cta_url, $cta_label, $footer_note),
            $mailer->build_notification_text($title, $message, $details, $cta_url, $cta_label, $footer_note)
        );

        if (!empty($args['from']) && is_array($args['from']) && !empty($args['from']['address'])) {
            $mailer->from((string) $args['from']['address'], (string) ($args['from']['name'] ?? ''));
        }

        if (!empty($args['reply_to'])) {
            if (is_array($args['reply_to']) && !empty($args['reply_to']['address'])) {
                $mailer->replyTo((string) $args['reply_to']['address'], (string) ($args['reply_to']['name'] ?? ''));
            } elseif (is_string($args['reply_to'])) {
                $mailer->replyTo($args['reply_to']);
            }
        }

        foreach ($attachments as $attachment) {
            if (is_string($attachment)) {
                $mailer->attach($attachment);
                continue;
            }

            if (is_array($attachment) && !empty($attachment['path'])) {
                $mailer->attach(
                    (string) $attachment['path'],
                    (string) ($attachment['filename'] ?? ''),
                    (string) ($attachment['mime'] ?? '')
                );
            }
        }

        foreach ($headers as $name => $value) {
            if (is_string($name) && '' !== $name && is_scalar($value)) {
                $mailer->header($name, (string) $value);
            }
        }

        return $mailer->send();
    }

    /**
     * Send a branded report email, optionally with an attached file.
     *
     * @param array $args
     * @return bool
     */
    public static function report(array $args): bool {
        $attachments = is_array($args['attachments'] ?? null) ? $args['attachments'] : [];

        if (!empty($args['file_path']) && is_string($args['file_path'])) {
            $attachments[] = [
                'path'     => $args['file_path'],
                'filename' => (string) ($args['filename'] ?? basename($args['file_path'])),
                'mime'     => (string) ($args['mime'] ?? ''),
            ];
        }

        $args['attachments'] = $attachments;
        $args['tone']        = (string) ($args['tone'] ?? 'info');

        if (empty($args['cta_label']) && !empty($args['cta_url'])) {
            $args['cta_label'] = __('Open Report', 'ultraguard-security-suite');
        }

        return self::notification($args);
    }

    /**
     * Send test email (for debugging).
     *
     * @param string $to_address
     * @return bool
     */
    public static function test(string $to_address): bool {
        $site = get_bloginfo('name');
        $html = self::make()->build_notification_html(
            'Test Email',
            'This is a test email from UltraGuard Pro.',
            [
                'Time' => current_time('mysql'),
                'Site' => $site,
                'PHP Version' => PHP_VERSION,
                'WordPress Version' => get_bloginfo('version'),
            ],
            'info'
        );

        return self::make()
            ->to($to_address)
            ->subject('[' . $site . '] Test Email from UltraGuard Pro')
            ->html($html)
            ->send();
    }

    // =========================================================================
    // RESET & UTILITY METHODS
    // =========================================================================

    /**
     * Reset builder state.
     *
     * @return static
     */
    public function reset(): self {
        $this->to = [];
        $this->cc = [];
        $this->bcc = [];
        $this->subject = '';
        $this->body = '';
        $this->content_type = self::TYPE_HTML;
        $this->charset = self::CHARSET;
        $this->from = [];
        $this->reply_to = [];
        $this->attachments = [];
        $this->extra_headers = [];
        $this->last_error = null;
        $this->template_vars = [];
        $this->auto_wrap = true;
        $this->format = 'html';
        $this->plain_text = '';

        $this->apply_plugin_defaults();
        return $this;
    }

    /**
     * Validate before sending.
     *
     * @return bool
     */
    public function validate(): bool {
        if (empty($this->to)) {
            $this->last_error = new \WP_Error('no_recipient', 'No recipient specified');
            return false;
        }

        if (empty($this->subject)) {
            $this->last_error = new \WP_Error('no_subject', 'No subject specified');
            return false;
        }

        if (empty($this->body) && empty($this->plain_text)) {
            $this->last_error = new \WP_Error('no_body', 'No body content specified');
            return false;
        }

        return true;
    }

    /**
     * Get last error.
     *
     * @return \WP_Error|null
     */
    public function getLastError(): ?\WP_Error {
        return $this->last_error;
    }

    /**
     * Preview headers without sending.
     *
     * @return array
     */
    public function previewHeaders(): array {
        return $this->build_headers();
    }

    /**
     * Preview recipients without sending.
     *
     * @return string
     */
    public function previewTo(): string {
        return $this->build_address_list($this->to);
    }

    /**
     * Get email statistics.
     *
     * @return array
     */
    public static function getStats(): array {
        return self::$stats;
    }

    /**
     * Set global error handler.
     *
     * @param callable $handler
     * @return void
     */
    public static function setErrorHandler(callable $handler): void {
        self::$error_handler = $handler;
    }

    /**
     * Add global header to all emails.
     *
     * @param string $name
     * @param string $value
     * @return void
     */
    public static function addGlobalHeader(string $name, string $value): void {
        self::$global_headers[$name] = $value;
    }

    // =========================================================================
    // FILTER CALLBACKS (PUBLIC FOR WORDPRESS)
    // =========================================================================

    /**
     * Filter content type.
     *
     * @internal
     * @return string
     */
    public function _filter_content_type(): string {
        return $this->content_type;
    }

    /**
     * Filter charset.
     *
     * @internal
     * @return string
     */
    public function _filter_charset(): string {
        return $this->charset;
    }

    /**
     * Capture error.
     *
     * @internal
     * @param \WP_Error $error
     */
    public function _capture_error(\WP_Error $error): void {
        $this->last_error = $error;

        if (self::$error_handler) {
            call_user_func(self::$error_handler, $error, $this);
        }
    }

    /**
     * Setup multipart email.
     *
     * @internal
     * @param PHPMailer $phpmailer
     */
    public function _setup_multipart($phpmailer): void {
        $phpmailer->isHTML(true);
        $phpmailer->AltBody = $this->plain_text;
    }

    // =========================================================================
    // PRIVATE METHODS
    // =========================================================================

    /**
     * Apply plugin defaults.
     */
    private function apply_plugin_defaults(): void {
        $from_name = $this->resolve_default_from_name();
        $from_address = $this->resolve_default_from_address();

        if ($from_address) {
            $this->from = [
                'address' => $from_address,
                'name' => sanitize_text_field($from_name),
            ];
        }

        $this->extra_headers['Auto-Submitted'] = 'auto-generated';
        $this->extra_headers['Precedence'] = 'bulk';
    }

    private function resolve_default_from_name(): string {
        $site_name = sanitize_text_field(get_bloginfo('name'));
        return '' !== $site_name ? $site_name : 'WordPress';
    }

    private function resolve_default_from_address(): string {
        $site_host = $this->get_site_mail_host();
        $fallback = sanitize_email('no-reply@' . $site_host);
        $configured = [
            get_option('notifications_from_email', ''),
            get_option('ultraguard_mail_from_address', ''),
        ];

        foreach ($configured as $candidate) {
            $candidate = sanitize_email((string) $candidate);
            if ($candidate && is_email($candidate) && $this->is_same_mail_domain($candidate, $site_host)) {
                return $candidate;
            }
        }

        return is_email($fallback) ? $fallback : '';
    }

    private function get_site_mail_host(): string {
        $host = (string) wp_parse_url(home_url(), PHP_URL_HOST);
        $host = strtolower(preg_replace('/^www\./i', '', $host));
        return $host ?: 'localhost';
    }

    private function is_same_mail_domain(string $email, string $site_host): bool {
        $parts = explode('@', strtolower($email));
        $email_domain = $parts[1] ?? '';

        if ('' === $email_domain || '' === $site_host) {
            return false;
        }

        return $email_domain === $site_host || str_ends_with($email_domain, '.' . $site_host);
    }

    /**
     * Parse recipients from various formats.
     *
     * @param string|array $input
     * @param string $name
     * @return array
     */
    private function parse_recipients($input, string $name = ''): array {
        if (is_string($input)) {
            $email = sanitize_email($input);
            return $email ? [['address' => $email, 'name' => sanitize_text_field($name)]] : [];
        }

        if (!is_array($input)) {
            return [];
        }

        // Single recipient array
        if (isset($input['address'])) {
            $email = sanitize_email($input['address']);
            return $email ? [[
                'address' => $email,
                'name' => sanitize_text_field($input['name'] ?? ''),
            ]] : [];
        }

        // Array of recipients
        $result = [];
        foreach ($input as $item) {
            if (is_string($item)) {
                $email = sanitize_email($item);
                if ($email) {
                    $result[] = ['address' => $email, 'name' => ''];
                }
            } elseif (is_array($item) && isset($item['address'])) {
                $email = sanitize_email($item['address']);
                if ($email) {
                    $result[] = [
                        'address' => $email,
                        'name' => sanitize_text_field($item['name'] ?? ''),
                    ];
                }
            }
        }

        return $result;
    }

    /**
     * Build address list string.
     *
     * @param array $recipients
     * @return string
     */
    private function build_address_list(array $recipients): string {
        $parts = [];
        foreach ($recipients as $r) {
            if (empty($r['address'])) {
                continue;
            }
            $parts[] = $r['name']
                ? sprintf('%s <%s>', $r['name'], $r['address'])
                : $r['address'];
        }
        return implode(', ', $parts);
    }

    /**
     * Build headers array.
     *
     * @return array
     */
    private function build_headers(): array {
        $headers = [];

        // From header
        if (!empty($this->from['address'])) {
            $headers[] = $this->from['name']
                ? sprintf('From: %s <%s>', $this->from['name'], $this->from['address'])
                : sprintf('From: %s', $this->from['address']);
        }

        // Reply-To header
        if (!empty($this->reply_to['address'])) {
            $headers[] = $this->reply_to['name']
                ? sprintf('Reply-To: %s <%s>', $this->reply_to['name'], $this->reply_to['address'])
                : sprintf('Reply-To: %s', $this->reply_to['address']);
        }

        // CC
        $cc = $this->build_address_list($this->cc);
        if ($cc) {
            $headers[] = 'Cc: ' . $cc;
        }

        // BCC
        $bcc = $this->build_address_list($this->bcc);
        if ($bcc) {
            $headers[] = 'Bcc: ' . $bcc;
        }

        // Global headers
        foreach (self::$global_headers as $name => $value) {
            $headers[] = $name . ': ' . $value;
        }

        // Custom headers
        foreach ($this->extra_headers as $name => $value) {
            $headers[] = $name . ': ' . $value;
        }

        // Add X-Mailer
        $version = defined('ULTRAGUARD_PRO_VERSION') ? ULTRAGUARD_PRO_VERSION : '';
        $headers[] = 'X-Mailer: UltraGuard Pro ' . $version;

        // Auto-response suppression
        $headers[] = 'X-Auto-Response-Suppress: OOF, DR, RN, NRN, AutoReply';

        return $headers;
    }

    /**
     * Prepare body for sending.
     *
     * @return string
     */
    private function prepare_body(): string {
        if ($this->content_type === self::TYPE_HTML && $this->auto_wrap) {
            return $this->ensure_html_wrapper($this->body);
        }
        return $this->body;
    }

    /**
     * Add WordPress filters.
     */
    private function add_filters(): void {
        add_filter('wp_mail_content_type', [$this, '_filter_content_type']);
        add_filter('wp_mail_charset', [$this, '_filter_charset']);
        add_action('wp_mail_failed', [$this, '_capture_error']);
    }

    /**
     * Remove WordPress filters.
     */
    private function remove_filters(): void {
        remove_filter('wp_mail_content_type', [$this, '_filter_content_type']);
        remove_filter('wp_mail_charset', [$this, '_filter_charset']);
        remove_action('wp_mail_failed', [$this, '_capture_error']);
    }

    /**
     * Update statistics.
     *
     * @param bool $success
     */
    private function update_stats(bool $success): void {
        self::$stats[$success ? 'sent' : 'failed']++;
        self::$stats['last_sent'] = current_time('mysql');
    }

    /**
     * Log debug info.
     *
     * @param bool $result
     */
    private function log_debug(bool $result): void {
        $to_list = implode(', ', array_column($this->to, 'address'));
        $status = $result ? 'SUCCESS' : 'FAILED';
        $error = $this->last_error ? $this->last_error->get_error_message() : 'none';
        $message = sprintf(
            '[UltraGuard Mail] %s - To: %s, Subject: %s, Error: %s',
            $status,
            $to_list,
            $this->subject,
            $error
        );

        if ( $result ) {
            \UltraguardPro\core\Logger::info( $message );
        } else {
            \UltraguardPro\core\Logger::error( $message );
        }
    }

    /**
     * Log error.
     *
     * @param string $message
     */
    private function log_error(string $message): void {
        if ($this->debug_mode) {
            \UltraguardPro\core\Logger::error( '[UltraGuard Mail] ' . $message );
        }
    }

    /**
     * Get MIME type for file.
     *
     * @param string $path
     * @return string
     */
    private function get_mime_type(string $path): string {
        $mime_types = [
            'pdf' => 'application/pdf',
            'zip' => 'application/zip',
            'txt' => 'text/plain',
            'csv' => 'text/csv',
            'json' => 'application/json',
            'png' => 'image/png',
            'jpg' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'gif' => 'image/gif',
        ];

        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
        return $mime_types[$ext] ?? 'application/octet-stream';
    }

    /**
     * Resolve template path.
     *
     * @param string $template
     * @return string|null
     */
    private function resolve_template_path(string $template): ?string {
        $slug = preg_replace('/[^a-z0-9\-_]/i', '', $template);

        // Check theme
        $theme_path = get_stylesheet_directory() . '/ultraguard-security-suite/emails/' . $slug . '.php';
        if (file_exists($theme_path)) {
            return $theme_path;
        }

        // Check plugin
        if (defined('ULTRAGUARD_PRO_PATH')) {
            $plugin_path = ULTRAGUARD_PRO_PATH . 'templates/emails/' . $slug . '.php';
            if (file_exists($plugin_path)) {
                return $plugin_path;
            }
        }

        return null;
    }

    /**
     * Render template.
     *
     * @param string $path
     * @param array $vars
     * @return string
     */
    private function render_template(string $path, array $vars): string {
        // phpcs:ignore WordPress.PHP.DontExtract
        extract($vars, EXTR_SKIP);
        ob_start();
        include $path;
        return (string) ob_get_clean();
    }

    /**
     * Ensure HTML is wrapped in full document.
     *
     * @param string $html
     * @return string
     */
    private function ensure_html_wrapper(string $html): string {
        if (stripos(ltrim($html), '<!DOCTYPE') === 0 || stripos(ltrim($html), '<html') === 0) {
            return $html;
        }
        return $this->apply_html_wrapper($html);
    }

    /**
     * Build HTML footer with license awareness.
     *
     * @return string
     */
    private function build_footer(): string {
        $site_name = esc_html(get_bloginfo('name'));
        $site_url = esc_url(get_bloginfo('url'));
        $year = gmdate('Y');
        $version = defined('ULTRAGUARD_PRO_VERSION') ? esc_html(ULTRAGUARD_PRO_VERSION) : '';
        $upgrade_url = esc_url('https://ultraguard.net/#pricing');
        $delay_days = self::FREE_DELAY_DAYS;
        $is_pro = class_exists(LicenseInfo::class) ? LicenseInfo::instance()->isPro() : false;

        // Plan badge
        $badge_bg = $is_pro ? '#0891b2' : '#64748b';
        $badge_label = $is_pro ? 'PRO' : 'FREE';

        $badge = sprintf(
            '<span style="display:inline-block;background:%s;color:#fff;font-size:10px;font-weight:700;letter-spacing:.6px;padding:2px 7px;border-radius:20px;text-transform:uppercase;vertical-align:middle;margin-left:5px;">%s</span>',
            $badge_bg,
            $badge_label
        );

        // Branding line
        $branding_line = sprintf(
            '<tr><td style="padding:18px 32px;background:#f3f7fb;text-align:center;color:#64748b;font-size:12px;line-height:1.9;border-top:1px solid #dbe6f0;">Sent by <a href="%s" style="color:#0f172a;text-decoration:none;font-weight:600;">%s</a> via <strong style="color:#0f172a;">UltraGuard</strong>%s %s &copy; %s</td></tr>',
            $site_url,
            $site_name,
            $badge,
            $version,
            $year
        );

        if ($is_pro) {
            return sprintf(
                '<table width="100%%" cellpadding="0" cellspacing="0" border="0" style="border-top:1px solid #dbe6f0;">
                    <tr><td style="padding:14px 32px 0;background:#f3f7fb;text-align:center;font-size:12px;color:#0f766e;font-weight:700;letter-spacing:.2px;">Real-time malware, antivirus and firewall definitions active.</td></tr>
                    %s
                </table>',
                $branding_line
            );
        }

        return sprintf(
            '<table width="100%%" cellpadding="0" cellspacing="0" border="0" style="border-top:1px solid #dbe6f0;">
                <tr><td style="padding:16px 32px;background:#fff7ed;border-top:3px solid #f59e0b;">
                    <table width="100%%" cellpadding="0" cellspacing="0" border="0">
                        <tr>
                            <td width="28" valign="top" style="font-size:20px;line-height:1;">!</td>
                            <td style="padding-left:10px;font-size:12px;color:#9a3412;line-height:1.8;">
                                <strong style="font-size:13px;color:#7c2d12;">Free plan definition updates are delayed by %d days.</strong><br>
                                Malware signatures, antivirus data and firewall rules reach your site <strong>%d days after release</strong>. Upgrade for real-time threat response and immediate rule coverage.
                            </td>
                        </tr>
                    </table>
                </td></tr>
                <tr><td style="padding:12px 32px;background:#ffedd5;text-align:center;">
                    <a href="%s" style="display:inline-block;background:#ea580c;color:#fff;font-size:12px;font-weight:700;padding:9px 20px;border-radius:999px;text-decoration:none;letter-spacing:.3px;">Upgrade to Pro for Real-Time Protection</a>
                </td></tr>
                %s
            </table>',
            $delay_days,
            $delay_days,
            $upgrade_url,
            $branding_line
        );
    }

    /**
     * Apply HTML wrapper.
     *
     * @param string $content
     * @param string $heading
     * @return string
     */
    private function apply_html_wrapper(string $content, string $heading = ''): string {
        $site_name = esc_html(get_bloginfo('name'));
        $site_host = esc_html((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
        $heading_html = $heading
            ? '<h2 style="color:#0f172a;margin:0 0 18px;font-size:22px;font-weight:800;line-height:1.3;letter-spacing:-0.02em;">' . esc_html($heading) . '</h2>'
            : '';

        $footer = $this->build_footer();

        // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed -- large HTML email template is maintained as a readable heredoc.
        return <<<HTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>{$site_name}</title>
    <style>
        @media only screen and (max-width: 600px) {
            .email-container { width: 100% !important; }
            .email-shell { padding: 18px !important; }
            .email-content { padding: 24px 18px !important; }
            .email-header { padding: 20px 18px !important; }
        }
    </style>
</head>
<body style="margin:0;padding:0;background:#edf4fb;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;color:#0f172a;">
    <div style="display:none;max-height:0;overflow:hidden;opacity:0;color:transparent;">UltraGuard security communication from {$site_name}</div>
    <table width="100%" cellpadding="0" cellspacing="0" border="0" style="background:linear-gradient(180deg,#081120 0%,#0f172a 180px,#edf4fb 180px);padding:32px 12px;" class="email-shell">
        <tr>
            <td align="center">
                <table class="email-container" width="640" cellpadding="0" cellspacing="0" border="0" style="max-width:640px;width:100%;background:#ffffff;border-radius:22px;overflow:hidden;box-shadow:0 24px 70px rgba(2,12,27,.22);border:1px solid #dbe6f0;">
                    <!-- Header -->
                    <tr>
                        <td class="email-header" style="background:linear-gradient(135deg,#081120 0%,#0f172a 45%,#0b7285 100%);padding:26px 32px 24px;">
                            <table width="100%" cellpadding="0" cellspacing="0" border="0">
                                <tr>
                                    <td align="left">
                                        <div style="display:inline-block;padding:6px 12px;border-radius:999px;background:rgba(255,255,255,.12);color:#bae6fd;font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">Security Communication</div>
                                        <div style="margin-top:14px;color:#ffffff;font-size:28px;font-weight:800;letter-spacing:-0.03em;line-height:1.1;">UltraGuard Pro</div>
                                        <div style="margin-top:8px;color:#cbd5e1;font-size:13px;line-height:1.7;">Protection update for {$site_name}</div>
                                    </td>
                                    <td align="right" valign="top">
                                        <div style="display:inline-block;border:1px solid rgba(186,230,253,.3);background:rgba(255,255,255,.08);padding:10px 14px;border-radius:16px;text-align:right;">
                                            <div style="color:#7dd3fc;font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;">Site</div>
                                            <div style="color:#ffffff;font-size:14px;font-weight:700;margin-top:4px;">{$site_host}</div>
                                        </div>
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>

                    <!-- Content -->
                    <tr>
                        <td class="email-content" style="padding:34px 32px 30px;color:#334155;font-size:15px;line-height:1.75;">
                            {$heading_html}
                            {$content}
                        </td>
                    </tr>

                    <!-- Footer -->
                    <tr>
                        <td style="padding:0;">
                            {$footer}
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
</body>
</html>
HTML;
    }

    /**
     * Build notification HTML.
     *
     * @param string $title
     * @param string $message
     * @param array $details
     * @param string $tone
     * @return string
     */
    private function build_notification_html(
        string $title,
        string $message,
        array $details = [],
        string $tone = 'info',
        string $cta_url = '',
        string $cta_label = '',
        string $footer_note = ''
    ): string {
        $accent_map = [
            'success' => '#16a34a',
            'warning' => '#d97706',
            'danger' => '#dc2626',
            'info' => '#0891b2',
        ];

        $accent = $accent_map[$tone] ?? $accent_map['info'];
        $soft_map = [
            'success' => '#ecfdf5',
            'warning' => '#fff7ed',
            'danger' => '#fef2f2',
            'info' => '#ecfeff',
        ];
        $soft = $soft_map[$tone] ?? $soft_map['info'];
        $title = esc_html($title);
        $message = esc_html($message);

        // Build details table
        $rows = '';
        foreach ($details as $label => $value) {
            $label = esc_html((string) $label);
            $value = is_array($value) ? esc_html(implode(', ', $value)) : esc_html((string) $value);
            $rows .= sprintf(
                '<tr><td style="padding:9px 14px;font-weight:600;color:#555;width:38%%;border-bottom:1px solid #f0f0f0;white-space:nowrap;font-size:13px;">%s</td><td style="padding:9px 14px;color:#222;border-bottom:1px solid #f0f0f0;font-size:13px;">%s</td></tr>',
                $label,
                $value
            );
        }

        $detail_table = $rows ? sprintf(
            '<table width="100%%" cellpadding="0" cellspacing="0" border="0" style="margin-top:24px;border:1px solid #dbe6f0;border-radius:16px;overflow:hidden;background:#ffffff;">%s</table>',
            $rows
        ) : '';

        $cta = '';
        if ('' !== $cta_url) {
            $cta = sprintf(
                '<div style="margin-top:24px;"><a href="%s" style="display:inline-block;background:%s;color:#ffffff;font-size:13px;font-weight:700;padding:12px 20px;border-radius:999px;text-decoration:none;letter-spacing:.02em;">%s</a></div>',
                esc_url($cta_url),
                esc_attr($accent),
                esc_html($cta_label ?: __('Open UltraGuard Dashboard', 'ultraguard-security-suite'))
            );
        }

        $note = '';
        if ('' !== $footer_note) {
            $note = sprintf(
                '<p style="margin:22px 0 0;color:#64748b;font-size:12px;line-height:1.8;">%s</p>',
                esc_html($footer_note)
            );
        }

        $inner = sprintf(
            '<div style="border:1px solid #dbe6f0;border-radius:18px;padding:22px 22px 20px;background:%s;box-shadow:inset 0 1px 0 rgba(255,255,255,.55);">
                <div style="display:inline-block;padding:6px 11px;border-radius:999px;background:#ffffff;color:%s;font-size:11px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;">UltraGuard Notice</div>
                <h2 style="margin:14px 0 8px;color:#0f172a;font-size:22px;font-weight:800;line-height:1.3;letter-spacing:-0.02em;">%s</h2>
                <p style="margin:0;color:#475569;font-size:14px;line-height:1.8;">%s</p>
            </div>
            %s',
            $soft,
            $accent,
            $title,
            $message,
            $detail_table . $cta . $note
        );

        return $this->apply_html_wrapper($inner);
    }

    /**
     * Build a plain-text version of a branded notification.
     *
     * @param string $title
     * @param string $message
     * @param array  $details
     * @param string $cta_url
     * @param string $cta_label
     * @param string $footer_note
     * @return string
     */
    private function build_notification_text(
        string $title,
        string $message,
        array $details = [],
        string $cta_url = '',
        string $cta_label = '',
        string $footer_note = ''
    ): string {
        $lines = [ trim($title), '', trim($message) ];

        foreach ($details as $label => $value) {
            if ( null === $value ) {
                continue;
            }

            if ( is_array( $value ) && empty( $value ) ) {
                continue;
            }

            if ( ! is_array( $value ) && '' === (string) $value ) {
                continue;
            }

            $lines[] = sprintf(
                '%s: %s',
                wp_strip_all_tags((string) $label),
                wp_strip_all_tags(is_array($value) ? implode(', ', $value) : (string) $value)
            );
        }

        if ('' !== $cta_url) {
            $lines[] = '';
            $lines[] = trim(($cta_label ?: __('Open UltraGuard Dashboard', 'ultraguard-security-suite')) . ': ' . $cta_url);
        }

        if ('' !== $footer_note) {
            $lines[] = '';
            $lines[] = wp_strip_all_tags($footer_note);
        }

        return implode("\n", $lines);
    }

    /**
     * Build promotion HTML.
     *
     * @param array $data
     * @return string
     */
    private function build_promotion_html(array $data = []): string {
        $upgrade_url = esc_url($data['upgrade_url'] ?? 'https://ultraguard.net/#pricing');
        $name = esc_html($data['name'] ?? '');
        $greeting = $name ? "Hi {$name}," : 'Hi there,';
        $delay_days = self::FREE_DELAY_DAYS;

        $headline = esc_html(
            $data['headline'] ?? 'Your site deserves real-time protection.'
        );

        $subheadline = esc_html(
            $data['subheadline'] ??
            "You're on the Free plan — malware, antivirus & firewall definitions arrive within 24 hours."
        );

        $cta_label = esc_html($data['cta_label'] ?? '🚀 Upgrade to Pro — See Plans');

        // Features
        $features = $data['features'] ?? [
            ['icon' => '⚡', 'title' => 'Real-time definitions', 'desc' => "Malware, antivirus &amp; firewall rules the moment they're released — zero delay."],
            ['icon' => '🔥', 'title' => 'Advanced WAF', 'desc' => 'Web Application Firewall with automatic rule updates and virtual patching.'],
            ['icon' => '🦠', 'title' => 'Deep malware scanner', 'desc' => 'Full-site deep scan with one-click auto-clean for infected files.'],
            ['icon' => '🔐', 'title' => 'Login hardening &amp; 2FA', 'desc' => 'Brute-force lockout, CAPTCHA, and two-factor authentication.'],
            ['icon' => '📊', 'title' => 'Weekly security reports', 'desc' => 'Detailed reports with threat timeline and remediation history.'],
            ['icon' => '💬', 'title' => 'Priority support (4 hrs)', 'desc' => 'Dedicated support queue with guaranteed 4-hour first response.'],
        ];

        $feature_rows = '';
        foreach (array_chunk($features, 2) as $pair) {
            $cells = '';
            foreach ($pair as $f) {
                $fi = esc_html($f['icon'] ?? '•');
                $ft = esc_html($f['title'] ?? '');
                $fd = $f['desc'] ?? '';
                $cells .= sprintf(
                    '<td width="50%%" valign="top" style="padding:10px 14px 10px 0;">
                        <table cellpadding="0" cellspacing="0" border="0"><tr>
                            <td width="32" valign="top" style="font-size:22px;line-height:1;padding-top:2px;">%s</td>
                            <td style="padding-left:10px;">
                                <div style="font-size:13px;font-weight:700;color:#1e293b;margin-bottom:3px;">%s</div>
                                <div style="font-size:12px;color:#64748b;line-height:1.5;">%s</div>
                            </td>
                        </tr></table>
                    </td>',
                    $fi,
                    $ft,
                    $fd
                );
            }
            if (count($pair) === 1) {
                $cells .= '<td width="50%"></td>';
            }
            $feature_rows .= "<tr>{$cells}</tr>";
        }

        // Comparison table
        $comparison = $data['comparison'] ?? [
            ['label' => 'Definition updates', 'free' => "within 24 hours", 'pro' => 'Real-time ✓'],
            ['label' => 'Malware scanner', 'free' => 'Basic', 'pro' => 'Deep + Auto-clean ✓'],
            ['label' => 'Firewall rules', 'free' => "within 24 hours", 'pro' => 'Instant ✓'],
            ['label' => 'Login protection', 'free' => 'Limiter only', 'pro' => '2FA + CAPTCHA ✓'],
            ['label' => 'Security reports', 'free' => '—', 'pro' => 'Weekly PDF ✓'],
            ['label' => 'Support', 'free' => 'Community forums', 'pro' => 'Priority (4 hrs) ✓'],
        ];

        $compare_rows = '';
        foreach ($comparison as $row) {
            $cl = esc_html($row['label'] ?? '');
            $cf = esc_html($row['free'] ?? '—');
            $cp = esc_html($row['pro'] ?? '—');
            $pro_style = str_contains($row['pro'] ?? '', '✓')
                ? 'color:#16a34a;font-weight:700;'
                : 'color:#4f46e5;font-weight:600;';
            $compare_rows .= sprintf(
                '<tr>
                    <td style="padding:9px 14px;color:#374151;font-size:13px;border-bottom:1px solid #f0f0f0;">%s</td>
                    <td style="padding:9px 14px;color:#dc2626;font-size:13px;text-align:center;border-bottom:1px solid #f0f0f0;">%s</td>
                    <td style="padding:9px 14px;font-size:13px;text-align:center;background:#f5f3ff;border-bottom:1px solid #ede9fe;%s">%s</td>
                </tr>',
                $cl,
                $cf,
                $pro_style,
                $cp
            );
        }

        $inner = sprintf(
            '<p style="margin:0 0 24px;font-size:15px;color:#334155;">%s</p>

            <table width="100%%" cellpadding="0" cellspacing="0" border="0"
                   style="background:linear-gradient(135deg,#1a1a2e 0%%,#16213e 60%%,#0f3460 100%%);
                          border-radius:8px;overflow:hidden;margin-bottom:28px;">
                <tr><td style="padding:36px 32px;text-align:center;">
                    <h2 style="margin:0 0 10px;color:#fff;font-size:22px;font-weight:700;line-height:1.4;">%s</h2>
                    <p style="margin:0 0 24px;color:#94a3b8;font-size:14px;line-height:1.6;">%s</p>
                    <a href="%s"
                       style="display:inline-block;background:#f59e0b;color:#fff;font-weight:700;
                              font-size:15px;padding:13px 36px;border-radius:6px;
                              text-decoration:none;letter-spacing:.3px;">%s</a>
                    <p style="margin:12px 0 0;color:#64748b;font-size:11px;">
                      30-day money-back guarantee &bull; Cancel anytime
                    </p>
                </td></tr>
            </table>

            <h3 style="margin:0 0 16px;font-size:13px;font-weight:700;color:#1e293b;
                       text-transform:uppercase;letter-spacing:.6px;">Everything you get with Pro</h3>
            <table width="100%%" cellpadding="0" cellspacing="0" border="0" style="margin-bottom:28px;">
                %s
            </table>

            <h3 style="margin:0 0 12px;font-size:13px;font-weight:700;color:#1e293b;
                       text-transform:uppercase;letter-spacing:.6px;">Free vs Pro</h3>
            <table width="100%%" cellpadding="0" cellspacing="0" border="0"
                   style="border:1px solid #e8ecf0;border-radius:6px;overflow:hidden;margin-bottom:28px;">
                <tr style="background:#f8fafc;">
                    <td style="padding:9px 14px;font-weight:700;font-size:12px;color:#64748b;
                               text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #e2e8f0;"></td>
                    <td style="padding:9px 14px;font-weight:700;font-size:12px;color:#64748b;text-align:center;
                               text-transform:uppercase;letter-spacing:.5px;border-bottom:2px solid #e2e8f0;">Free</td>
                    <td style="padding:9px 14px;font-weight:700;font-size:12px;color:#4f46e5;text-align:center;
                               text-transform:uppercase;letter-spacing:.5px;
                               background:#ede9fe;border-bottom:2px solid #ddd6fe;">Pro</td>
                </tr>
                %s
            </table>

            <div style="text-align:center;padding:8px 0 4px;">
                <a href="%s"
                   style="display:inline-block;background:#4f46e5;color:#fff;font-weight:700;
                          font-size:15px;padding:13px 40px;border-radius:6px;
                          text-decoration:none;letter-spacing:.3px;">Upgrade to Pro Now</a>
                <p style="margin:12px 0 0;font-size:12px;color:#94a3b8;">
                    Questions? Reply to this email or visit
                    <a href="https://ultraguard.net" style="color:#4f46e5;text-decoration:none;">ultraguard.net</a>
                </p>
            </div>',
            $greeting,
            $headline,
            $subheadline,
            $upgrade_url,
            $cta_label,
            $feature_rows,
            $compare_rows,
            $upgrade_url
        );

        return $this->apply_html_wrapper($inner);
    }
}
