<?php
/**
 * Email Logs Module
 *
 * Logs all emails sent through WordPress for debugging and monitoring.
 *
 * @package EmailLogs
 * @since 1.0.0
 */

namespace EmailLogs;

use WP_PowerSuite\Core\Contracts\DataLocationsInterface;
use WP_PowerSuite\Core\AbstractModule;
use WP_PowerSuite\Core\NetworkScope;
use EmailLogs\Includes\EmailLogService;
use EmailLogs\Includes\EmailLogsListTable;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

require_once __DIR__ . '/includes/EmailLogService.php';
require_once __DIR__ . '/includes/EmailLogsListTable.php';

class Module extends AbstractModule implements DataLocationsInterface {

	private const MODULE_ID = 'email-logs';

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Email Logs', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return '1.4.16';
	}

	public function getDescription(): string {
		return __( 'History of WordPress-sent email with recipients, subjects, and timestamps for support and debugging.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		// Cron/REST/CLI can send third-party plugin mail via wp_mail().
		return [ 'admin', 'frontend', 'ajax', 'rest', 'cron', 'cli' ];
	}

	public function getDependencies(): array {
		return [];
	}

	private function isLicenseActive(): bool {
		return function_exists( 'wp_powersuite_is_license_valid' ) && wp_powersuite_is_license_valid();
	}

	public function getDataLocations(): array {
		return [
			'options' => [ EmailLogService::get_option_key() ],
			'tables'  => [ 'wpps_email_logs' ],
		];
	}

	protected function registerHooks(): void {
		if ( ! $this->isLicenseActive() ) {
			return;
		}

		add_action( 'init', [ $this, 'maybeCreateTable' ], 999 );
		add_filter( 'wp_mail', [ $this, 'logEmail' ], 10, 1 );
		// Capture final PHPMailer headers/transport after other SMTP plugins configure it.
		$phpmailer_priority = (int) apply_filters( 'wp_powersuite_email_logs_phpmailer_priority', 9999 );
		add_action( 'phpmailer_init', [ $this, 'onPhpMailerInit' ], $phpmailer_priority, 1 );
		// Run before mark_sent/mark_failed (priority 10) so Message-ID and final state are stored.
		add_action( 'wp_mail_failed', [ $this, 'onMailCaptureBeforeFinish' ], 5, 1 );
		add_action( 'wp_mail_succeeded', [ $this, 'onMailCaptureBeforeFinish' ], 5, 1 );
		add_action( 'wp_mail_failed', [ $this, 'onMailFailed' ], 10, 1 );
		add_action( 'wp_mail_succeeded', [ $this, 'onMailSucceeded' ], 10, 1 );
		add_action( 'wp_powersuite_email_delivery_log_enrich', [ $this, 'onDeliveryLogEnrich' ], 10, 3 );
		// Simulation intentionally skips wp_mail_succeeded; still finalize the pending log row.
		add_action( 'wp_powersuite_email_delivery_simulated', [ $this, 'onDeliverySimulated' ], 10, 0 );
		add_action( EmailLogService::CRON_PRUNE, [ EmailLogService::class, 'prune_logs' ] );
		add_action( EmailLogService::CRON_RETRY_FAILED, [ EmailLogService::class, 'cron_retry_failed' ] );
		EmailLogService::schedule_prune();
		EmailLogService::schedule_retry_failed();
		EmailLogService::register_privacy_hooks();

		add_action( 'wp_ajax_wpps_email_logs_get', [ $this, 'ajaxGetLog' ] );

		if ( is_admin() ) {
			add_action( $this->adminMenuHook(), [ $this, 'addAdminMenu' ], 20 );
			add_action( 'admin_enqueue_scripts', [ $this, 'enqueueScripts' ] );
			add_action( 'wp_dashboard_setup', [ $this, 'registerDashboardWidget' ] );
			add_action( 'admin_post_wpps_email_logs_save_settings', [ $this, 'handleSaveSettings' ] );
			add_action( 'admin_post_wpps_email_logs_export', [ $this, 'handleExport' ] );
			add_filter( 'set-screen-option', [ $this, 'setScreenOption' ], 10, 3 );
		}
	}

	public function registerDashboardWidget(): void {
		if ( ! $this->canManagePlugin() || ! EmailLogService::is_dashboard_widget_enabled() ) {
			return;
		}
		wp_add_dashboard_widget(
			'wpps_email_logs_dashboard',
			__( 'Email Logs', 'wp-powersuite' ),
			[ $this, 'renderDashboardWidget' ]
		);
	}

	public function renderDashboardWidget(): void {
		$stats       = EmailLogService::get_dashboard_stats();
		$logs_url    = NetworkScope::adminUrl( 'admin.php', [ 'page' => 'powersuite-email-logs' ] );
		$sent_url    = NetworkScope::adminUrl( 'admin.php', [ 'page' => 'powersuite-email-logs', 'status' => 'sent' ] );
		$fail_url    = NetworkScope::adminUrl( 'admin.php', [ 'page' => 'powersuite-email-logs', 'status' => 'failed' ] );
		$bounce_url  = NetworkScope::adminUrl( 'admin.php', [ 'page' => 'powersuite-email-logs', 'status' => 'bounced' ] );
		$failed_count = (int) ( $stats['failed'] ?? 0 );
		$cards       = [
			[
				'key'   => 'today',
				'value' => (int) ( $stats['today'] ?? 0 ),
				'label' => __( 'Today', 'wp-powersuite' ),
				'icon'  => 'dashicons-clock',
				'url'   => $logs_url,
			],
			[
				'key'   => 'sent',
				'value' => (int) ( $stats['sent'] ?? 0 ),
				'label' => __( 'Sent', 'wp-powersuite' ),
				'icon'  => 'dashicons-yes-alt',
				'url'   => $sent_url,
			],
			[
				'key'   => 'failed',
				'value' => $failed_count,
				'label' => __( 'Failed', 'wp-powersuite' ),
				'icon'  => 'dashicons-warning',
				'url'   => $fail_url,
			],
			[
				'key'   => 'bounced',
				'value' => (int) ( $stats['bounced'] ?? 0 ),
				'label' => __( 'Bounced', 'wp-powersuite' ),
				'icon'  => 'dashicons-dismiss',
				'url'   => $bounce_url,
			],
		];
		?>
		<div class="wpps-el-dash">
			<p class="description wpps-el-dash-intro">
				<?php esc_html_e( 'Recent WordPress email activity from Email Logs.', 'wp-powersuite' ); ?>
			</p>
			<div class="wpps-el-dash-stats">
				<?php foreach ( $cards as $card ) : ?>
					<div class="wpps-el-dash-stat wpps-el-dash-stat--<?php echo esc_attr( $card['key'] ); ?>">
						<a href="<?php echo esc_url( $card['url'] ); ?>">
							<span class="wpps-el-dash-icon" aria-hidden="true">
								<span class="dashicons <?php echo esc_attr( $card['icon'] ); ?>"></span>
							</span>
							<span class="wpps-el-dash-value"><?php echo esc_html( number_format_i18n( $card['value'] ) ); ?></span>
							<span class="wpps-el-dash-label"><?php echo esc_html( $card['label'] ); ?></span>
						</a>
					</div>
				<?php endforeach; ?>
			</div>
			<p class="wpps-el-dash-actions">
				<a class="button button-primary" href="<?php echo esc_url( $logs_url ); ?>"><?php esc_html_e( 'View logs', 'wp-powersuite' ); ?></a>
				<?php if ( $failed_count > 0 ) : ?>
					<a class="button" href="<?php echo esc_url( $fail_url ); ?>"><?php esc_html_e( 'Failed only', 'wp-powersuite' ); ?></a>
				<?php endif; ?>
			</p>
		</div>
		<?php
	}

	/** @param array{to?:mixed,subject?:string,message?:string,headers?:string|array} $args */
	public function logEmail( array $args ): array {
		return EmailLogService::log_email( $args );
	}

	/**
	 * @param \PHPMailer\PHPMailer\PHPMailer $phpmailer
	 */
	public function onPhpMailerInit( $phpmailer ): void {
		if ( is_object( $phpmailer ) ) {
			EmailLogService::capture_phpmailer( $phpmailer );
		}
	}

	/**
	 * @param mixed $arg WP_Error on failure, mail_data array on success.
	 */
	public function onMailCaptureBeforeFinish( $arg = null ): void {
		unset( $arg );
		EmailLogService::capture_global_phpmailer();
	}

	public function onMailFailed( \WP_Error $error ): void {
		EmailLogService::mark_failed( $error );
	}

	public function onMailSucceeded( array $mail_data ): void {
		unset( $mail_data );
		EmailLogService::mark_sent();
	}

	/**
	 * @param array<string, mixed> $data
	 * @param mixed                $result
	 * @param mixed                $provider
	 */
	public function onDeliveryLogEnrich( $data, $result = null, $provider = null ): void {
		unset( $result, $provider );
		if ( is_array( $data ) ) {
			EmailLogService::enrich_pending( $data );
		}
	}

	public function onDeliverySimulated(): void {
		EmailLogService::mark_sent();
	}

	public function maybeCreateTable(): void {
		EmailLogService::create_table();
	}

	public function addAdminMenu(): void {
		$hook = add_submenu_page(
			'powersuite',
			__( 'Email Logs', 'wp-powersuite' ),
			__( 'Email Logs', 'wp-powersuite' ),
			$this->adminCapability(),
			'powersuite-email-logs',
			[ $this, 'renderAdminPage' ]
		);
		if ( is_string( $hook ) && $hook !== '' ) {
			add_action( "load-$hook", [ $this, 'onLoadAdminPage' ] );
		}
	}

	/**
	 * Screen options + bulk action processing before headers are sent.
	 */
	public function onLoadAdminPage(): void {
		if ( ! $this->canManagePlugin() || ! $this->isLicenseActive() ) {
			return;
		}

		add_screen_option(
			'per_page',
			[
				'label'   => __( 'Logs per page', 'wp-powersuite' ),
				'default' => 20,
				'option'  => 'email_logs_per_page',
			]
		);

		$this->processAdminActions();
	}

	/**
	 * @param mixed  $status
	 * @param string $option
	 * @param mixed  $value
	 * @return mixed
	 */
	public function setScreenOption( $status, $option, $value ) {
		if ( $option === 'email_logs_per_page' ) {
			return max( 5, min( 100, (int) $value ) );
		}
		return $status;
	}

	private function processAdminActions(): void {
		$action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( (string) $_REQUEST['action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$action2 = isset( $_REQUEST['action2'] ) ? sanitize_key( wp_unslash( (string) $_REQUEST['action2'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $action === '-1' ) {
			$action = $action2;
		}

		if ( $action === 'empty_logs' ) {
			check_admin_referer( 'wpps_email_logs_empty' );
			EmailLogService::delete_all_logs();
			wp_safe_redirect(
				add_query_arg(
					[
						'page'    => 'powersuite-email-logs',
						'emptied' => '1',
					],
					NetworkScope::adminUrl( 'admin.php' )
				)
			);
			exit;
		}

		if ( $action === 'resend' ) {
			$log_id = isset( $_REQUEST['log_id'] ) ? absint( wp_unslash( $_REQUEST['log_id'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			check_admin_referer( 'wpps_email_logs_resend_' . $log_id );
			$result = EmailLogService::resend_log( $log_id );
			$args   = [
				'page' => 'powersuite-email-logs',
			];
			if ( is_wp_error( $result ) ) {
				$args['resend_error'] = rawurlencode( $result->get_error_message() );
			} else {
				$args['resent'] = '1';
			}
			wp_safe_redirect( add_query_arg( $args, NetworkScope::adminUrl( 'admin.php' ) ) );
			exit;
		}

		if ( $action === 'delete' || $action2 === 'delete' ) {
			$list_table = new EmailLogsListTable();
			$list_table->process_bulk_action();
		}
	}

	public function enqueueScripts( string $hook ): void {
		$base = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';
		$is_logs_page = strpos( $hook, 'powersuite-email-logs' ) !== false;
		$is_dashboard = $hook === 'index.php' && EmailLogService::is_dashboard_widget_enabled();

		if ( ! $is_logs_page && ! $is_dashboard ) {
			return;
		}

		wp_enqueue_style( 'dashicons' );

		$style_deps = [ 'dashicons' ];

		// Only depend on core admin chrome when it is actually registered (or register it on the logs page).
		if ( $is_logs_page && $base !== '' && ! wp_style_is( 'wp-powersuite-admin', 'registered' ) ) {
			wp_register_style(
				'wp-powersuite-admin',
				$base . 'assets/admin/app.css',
				[ 'wp-admin' ],
				defined( 'WP_POWERSUITE_VERSION' ) ? WP_POWERSUITE_VERSION : '1.4.3'
			);
		}
		if ( wp_style_is( 'wp-powersuite-admin', 'registered' ) ) {
			wp_enqueue_style( 'wp-powersuite-admin' );
			$style_deps[] = 'wp-powersuite-admin';
		}

		wp_enqueue_style(
			'wpps-email-logs-admin',
			wp_powersuite_module_asset_url( __FILE__, 'assets/email-logs-admin.css' ),
			$style_deps,
			'1.4.17'
		);

		if ( ! $is_logs_page ) {
			return;
		}

		wp_enqueue_script( 'wpps-email-logs-admin', wp_powersuite_module_asset_url( __FILE__, 'assets/email-logs-admin.js' ), [], '1.4.17', true );
		wp_localize_script(
			'wpps-email-logs-admin',
			'wppsEmailLogs',
			[
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'nonce'   => wp_create_nonce( 'wpps_email_logs' ),
				'i18n'    => [
					'loading'         => __( 'Loading…', 'wp-powersuite' ),
					'loadError'       => __( 'Could not load log.', 'wp-powersuite' ),
					'details'         => __( 'Email details', 'wp-powersuite' ),
					'noSubject'       => __( '(No subject)', 'wp-powersuite' ),
					'noContent'       => __( '(No content)', 'wp-powersuite' ),
					'to'              => __( 'To', 'wp-powersuite' ),
					'from'            => __( 'From', 'wp-powersuite' ),
					'replyTo'         => __( 'Reply-To', 'wp-powersuite' ),
					'cc'              => __( 'Cc', 'wp-powersuite' ),
					'bcc'             => __( 'Bcc', 'wp-powersuite' ),
					'contentType'     => __( 'Content-Type', 'wp-powersuite' ),
					'date'            => __( 'Date', 'wp-powersuite' ),
					'provider'        => __( 'Provider', 'wp-powersuite' ),
					'transport'       => __( 'Transport', 'wp-powersuite' ),
					'connection'      => __( 'Connection', 'wp-powersuite' ),
					'envelope'        => __( 'Envelope', 'wp-powersuite' ),
					'routing'         => __( 'Routing', 'wp-powersuite' ),
					'messageId'       => __( 'Message ID', 'wp-powersuite' ),
					'duration'        => __( 'Duration', 'wp-powersuite' ),
					'retries'         => __( 'Retries', 'wp-powersuite' ),
					'fallback'        => __( 'Fallback', 'wp-powersuite' ),
					'yes'             => __( 'Yes', 'wp-powersuite' ),
					'error'           => __( 'Error', 'wp-powersuite' ),
					'headers'         => __( 'Headers', 'wp-powersuite' ),
					'noHeaders'       => __( 'No headers were captured for this message. The sender may have set From on PHPMailer after wp_mail() args, or used a custom mailer that bypasses WordPress.', 'wp-powersuite' ),
					'message'         => __( 'Message', 'wp-powersuite' ),
					'attachments'     => __( 'Attachments', 'wp-powersuite' ),
					'noAttachments'   => __( 'No attachments', 'wp-powersuite' ),
					'previewHtml'     => __( 'Preview HTML', 'wp-powersuite' ),
					'resend'          => __( 'Resend', 'wp-powersuite' ),
					'delete'          => __( 'Delete', 'wp-powersuite' ),
					'confirmDelete'   => __( 'Delete this log entry?', 'wp-powersuite' ),
					'copy'            => __( 'Copy', 'wp-powersuite' ),
					'copied'          => __( 'Copied', 'wp-powersuite' ),
					'contentDisabled' => __( 'Message body was not stored. Enable “Store email body content in logs” in settings to keep bodies for future sends.', 'wp-powersuite' ),
				],
			]
		);
	}

	public function renderAdminPage(): void {
		if ( ! $this->canManagePlugin() ) {
			wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-powersuite' ) );
		}
		if ( ! $this->isLicenseActive() ) {
			?>
			<div class="wrap">
				<h1><?php esc_html_e( 'Email Logs', 'wp-powersuite' ); ?></h1>
				<div class="notice notice-warning inline" style="margin:0;">
					<p>
						<?php esc_html_e( 'Email Logs requires an active license. Activate your license to view outgoing mail history.', 'wp-powersuite' ); ?>
						<a href="<?php echo esc_url( admin_url( 'admin.php?page=powersuite-license' ) ); ?>"><?php esc_html_e( 'Activate license', 'wp-powersuite' ); ?></a>
					</p>
				</div>
			</div>
			<?php
			return;
		}

		EmailLogService::create_table();

		$settings = EmailLogService::get_settings();
		$notice   = '';
		if ( isset( $_GET['saved'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$notice = __( 'Settings saved. Logs outside the retention window or entry cap were removed.', 'wp-powersuite' );
		} elseif ( isset( $_GET['deleted'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$notice = sprintf(
				/* translators: %d: number of deleted logs */
				__( '%d log(s) deleted.', 'wp-powersuite' ),
				(int) $_GET['deleted'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			);
		} elseif ( isset( $_GET['emptied'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$notice = __( 'All email logs deleted.', 'wp-powersuite' );
		} elseif ( isset( $_GET['resent'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$notice = __( 'Email resent successfully.', 'wp-powersuite' );
		} elseif ( ! empty( $_GET['resend_error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$notice = sanitize_text_field( rawurldecode( wp_unslash( (string) $_GET['resend_error'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		}

		$list_table = new EmailLogsListTable();
		$list_table->prepare_items();
		$stats     = EmailLogService::get_dashboard_stats();
		$providers = EmailLogService::distinct_providers();

		include __DIR__ . '/views/admin-page.php';
	}

	public function handleSaveSettings(): void {
		if ( ! $this->canManagePlugin() || ! check_admin_referer( 'wpps_email_logs_settings' ) ) {
			wp_die( esc_html__( 'Invalid request.', 'wp-powersuite' ) );
		}
		$limit = isset( $_POST['limit'] ) ? (int) sanitize_text_field( wp_unslash( (string) $_POST['limit'] ) ) : 1000;
		$days  = isset( $_POST['retention_days'] ) ? (int) sanitize_text_field( wp_unslash( (string) $_POST['retention_days'] ) ) : 30;
		EmailLogService::save_settings(
			[
				'limit'            => $limit,
				'retention_days'   => $days,
				'log_content'      => isset( $_POST['log_content'] ) ? 1 : 0,
				'dashboard_widget' => isset( $_POST['dashboard_widget'] ) && (string) wp_unslash( $_POST['dashboard_widget'] ) !== '0' ? 1 : 0, // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			]
		);
		wp_safe_redirect(
			add_query_arg(
				[ 'page' => 'powersuite-email-logs', 'saved' => '1' ],
				NetworkScope::adminUrl( 'admin.php' )
			)
		);
		exit;
	}

	public function handleExport(): void {
		if ( ! $this->canManagePlugin() || ! check_admin_referer( 'wpps_email_logs_export' ) ) {
			wp_die( esc_html__( 'Invalid request.', 'wp-powersuite' ) );
		}

		$csv      = EmailLogService::export_csv();
		$filename = 'email-logs-' . gmdate( 'Y-m-d' ) . '.csv';

		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $filename ) . '"' );
		echo "\xEF\xBB\xBF" . $csv;
		exit;
	}

	public function ajaxGetLog(): void {
		if ( ! $this->canManagePlugin() || ! check_ajax_referer( 'wpps_email_logs', 'nonce', false ) ) {
			wp_send_json_error( [ 'message' => __( 'Invalid request.', 'wp-powersuite' ) ] );
		}

		$id  = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
		$log = $id ? EmailLogService::get_log_by_id( $id ) : null;
		if ( ! $log ) {
			wp_send_json_error( [ 'message' => __( 'Log entry not found.', 'wp-powersuite' ) ] );
		}

		$ts = strtotime( (string) ( $log->sent_date ?? '' ) );
		$delete_url = wp_nonce_url(
			add_query_arg(
				[
					'page'    => 'powersuite-email-logs',
					'action'  => 'delete',
					'log_ids' => [ (int) $log->id ],
				],
				NetworkScope::adminUrl( 'admin.php' )
			),
			'bulk-email_logs'
		);
		$resend_url = wp_nonce_url(
			add_query_arg(
				[
					'page'   => 'powersuite-email-logs',
					'action' => 'resend',
					'log_id' => (int) $log->id,
				],
				NetworkScope::adminUrl( 'admin.php' )
			),
			'wpps_email_logs_resend_' . (int) $log->id
		);

		$status                   = sanitize_key( (string) ( $log->status ?? 'pending' ) );
		$delivery                 = sanitize_key( (string) ( $log->delivery_status ?? '' ) );
		$message                  = (string) ( $log->message ?? '' );
		$content_logging_disabled = EmailLogService::is_content_disabled_message( $message );

		$headers_raw = (string) ( $log->headers ?? '' );
		$headers_ui  = EmailLogService::headers_for_display( $headers_raw );
		$from_email  = (string) ( $log->from_email ?? '' );
		if ( $from_email === '' ) {
			$from_email = EmailLogService::extract_from_email( $headers_raw );
		}

		$attachments = EmailLogService::decode_attachments_meta( (string) ( $log->attachments ?? '' ) );
		$attachments_ui = [];
		foreach ( $attachments as $att ) {
			$attachments_ui[] = [
				'name'          => (string) ( $att['name'] ?? '' ),
				'size'          => (int) ( $att['size'] ?? 0 ),
				'size_label'    => EmailLogService::format_attachment_size( (int) ( $att['size'] ?? 0 ) ),
			];
		}

		wp_send_json_success(
			[
				'id'                        => (int) $log->id,
				'to_email'                  => (string) ( $log->to_email ?? '' ),
				'from_email'                => $from_email,
				'subject'                   => (string) ( $log->subject ?? '' ),
				'message'                   => $content_logging_disabled ? '' : $message,
				'headers'                   => $headers_raw,
				'headers_structured'        => $headers_ui,
				'attachments'               => $attachments_ui,
				'status'                    => $status,
				'status_label'              => ucfirst( $status ),
				'delivery_status'           => $delivery,
				'delivery_label'            => EmailLogService::label_for_delivery_status( $delivery ),
				'error_message'             => (string) ( $log->error_message ?? '' ),
				'sent_date'                 => (string) ( $log->sent_date ?? '' ),
				'sent_date_formatted'       => $ts ? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ) : '',
				'provider'                  => (string) ( $log->provider ?? '' ),
				'provider_message_id'       => (string) ( $log->provider_message_id ?? '' ),
				'duration_ms'               => (int) ( $log->duration_ms ?? 0 ),
				'retry_count'               => (int) ( $log->retry_count ?? 0 ),
				'fallback_used'             => ! empty( $log->fallback_used ),
				'transport'                 => (string) ( $log->transport ?? '' ),
				'connection_id'             => (string) ( $log->connection_id ?? '' ),
				'envelope_sender'           => (string) ( $log->envelope_sender ?? '' ),
				'routing_reason'            => (string) ( $log->routing_reason ?? '' ),
				'content_logging_disabled'  => $content_logging_disabled,
				'is_html'                   => EmailLogService::message_is_html( $message, $headers_raw ),
				'can_resend'                => EmailLogService::can_resend_log( $log ),
				'resend_url'                => $resend_url,
				'delete_url'                => $delete_url,
			]
		);
	}
}
