<?php
/**
 * Settings helpers for the Mail Doctor admin UI.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Admin\Modules;

use MailDoctor\API_Keys;
use MailDoctor\Helpers\Dependencies;
use MailDoctor\Helpers\Settings;
use MailDoctor\Profiles;
use MailDoctor\Retry;
use MailDoctor\Woo;

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

/**
 * Provides rendering, persistence, and supporting helpers for settings screens.
 */
trait Settings_Trait {


	/**
	 * Render settings tab with subtabs.
	 *
	 * @return void
	 */
	protected static function render_settings_tab(): void {
		$mail_doctor_active_tab              = 'settings';
		$mail_doctor_section                 = self::get_current_section();
		$mail_doctor_base_url                = self::page_url( 'settings' );
		$mail_doctor_settings                = self::get_settings();
		$mail_doctor_provider_options        = self::get_provider_options();
		$mail_doctor_transport_options       = self::get_transport_options();
		$mail_doctor_ses_regions             = self::get_ses_regions();
		$mail_doctor_sections                = self::get_settings_sections();
		$mail_doctor_profile_rows            = array();
			$mail_doctor_profile_choices     = Settings::profile_choices();
			$mail_doctor_active_profile      = Settings::get_active_profile();
			$mail_doctor_profile_assignments = Settings::get_profile_assignments();
		$mail_doctor_woocommerce_available   = Dependencies::is_woocommerce_available();
		$mail_doctor_woo_email_rows          = array();


		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only recipe prefill.
		$mail_doctor_recipe_key          = isset( $_GET['mail_doctor_recipe'] ) ? sanitize_key( wp_unslash( $_GET['mail_doctor_recipe'] ) ) : '';
		$mail_doctor_recipe_placeholders = array();

		if ( $mail_doctor_recipe_key ) {
			$mail_doctor_recipe_prefill = self::get_provider_recipe( $mail_doctor_recipe_key );

			if ( ! empty( $mail_doctor_recipe_prefill['settings'] ) && is_array( $mail_doctor_recipe_prefill['settings'] ) ) {
				$mail_doctor_settings = array_merge( $mail_doctor_settings, $mail_doctor_recipe_prefill['settings'] );
			}

			if ( ! empty( $mail_doctor_recipe_prefill['placeholders'] ) && is_array( $mail_doctor_recipe_prefill['placeholders'] ) ) {
				$mail_doctor_recipe_placeholders = $mail_doctor_recipe_prefill['placeholders'];
			}

			if ( ! empty( $mail_doctor_recipe_prefill['notice'] ) ) {
				add_settings_error(
					'maildoctor',
					'mail_doctor_recipe_' . $mail_doctor_recipe_key,
					$mail_doctor_recipe_prefill['notice'],
					'notice-info'
				);
			}
		}

		if ( 'woocommerce' === $mail_doctor_section && $mail_doctor_woocommerce_available ) {
			$mail_doctor_woo_email_rows     = Woo::get_email_toggle_data();
			$mail_doctor_woo_preview_emails = Woo::get_previewable_emails();
		}

		if ( 'profiles' === $mail_doctor_section && class_exists( Profiles::class ) ) {
			$mail_doctor_profile_rows = Profiles::all();
		}

		include MAIL_DOCTOR_PATH . 'templates/admin/settings-page.php';
	}

	/**
	 * Retrieve preset defaults for guides "Apply recipe" actions.
	 *
	 * @param string $key Recipe key.
	 * @return array<string,mixed>
	 */
	protected static function get_provider_recipe( string $key ): array {
		$recipes = array(
			'gmail'    => array(
				'settings'     => array(
					'provider'   => 'gmail',
					'transport'  => 'smtp',
					'host'       => 'smtp.gmail.com',
					'port'       => 587,
					'encryption' => 'tls',
					'auth'       => 'login',
					'username'   => 'you@example.com',
					'password'   => '',
				),
				'placeholders' => array(
					'password' => esc_html__( 'Paste your Google App Password', 'mail-doctor' ),
				),
				'notice'       => esc_html__( 'Loaded the Gmail recipe. Replace the sample username and add your App Password before saving.', 'mail-doctor' ),
			),
			'sendgrid' => array(
				'settings'     => array(
					'provider'   => 'sendgrid',
					'transport'  => 'smtp',
					'host'       => 'smtp.sendgrid.net',
					'port'       => 587,
					'encryption' => 'tls',
					'auth'       => 'login',
					'username'   => 'apikey',
					'password'   => '',
				),
				'placeholders' => array(
					'password' => esc_html__( 'Paste your SendGrid API key', 'mail-doctor' ),
				),
				'notice'       => esc_html__( 'Loaded the SendGrid recipe. Paste your API key into the password field before saving.', 'mail-doctor' ),
			),
			'mailgun'  => array(
				'settings'     => array(
					'provider'   => 'mailgun',
					'transport'  => 'smtp',
					'host'       => 'smtp.mailgun.org',
					'port'       => 587,
					'encryption' => 'tls',
					'auth'       => 'login',
					'username'   => 'postmaster@YOUR_DOMAIN',
					'password'   => '',
				),
				'placeholders' => array(
					'password' => esc_html__( 'Paste your Mailgun SMTP password', 'mail-doctor' ),
				),
				'notice'       => esc_html__( 'Loaded the Mailgun recipe. Swap YOUR_DOMAIN and add your SMTP password before saving.', 'mail-doctor' ),
			),
			'ses'      => array(
				'settings'     => array(
					'provider'   => 'ses',
					'transport'  => 'smtp',
					'host'       => 'email-smtp.us-east-1.amazonaws.com',
					'port'       => 587,
					'encryption' => 'tls',
					'auth'       => 'login',
					'username'   => 'SMTP Username',
					'password'   => '',
				),
				'placeholders' => array(
					'password' => esc_html__( 'Paste your Amazon SES SMTP password', 'mail-doctor' ),
				),
				'notice'       => esc_html__( 'Loaded the Amazon SES recipe. Paste the SMTP username and password from your SES console before saving.', 'mail-doctor' ),
			),
		);

		/**
		 * Filter provider recipes for the settings quick-apply feature.
		 *
		 * @since 1.0.0
		 *
		 * @param array<string,mixed> $recipe Recipe definition.
		 * @param string              $key Recipe key.
		 */
		$recipe = $recipes[ $key ] ?? array();

		return apply_filters( 'mail_doctor_settings_provider_recipe', $recipe, $key );
	}

	/**
	 * Render guides tab.
	 *
	 * @return void
	 */
	protected static function render_guides_tab(): void {
		$mail_doctor_active_tab = 'guides';
		$mail_doctor_base_url   = self::page_url( 'guides' );

		include MAIL_DOCTOR_PATH . 'templates/admin/guides.php';
	}

	/**
	 * Handle settings form submission.
	 *
	 * @return void
	 */
	public static function handle_settings_form(): void {
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Early exit check only; nonce verified via check_admin_referer() on line 202.
		if ( empty( $_POST['mail_doctor_settings_nonce'] ) ) {
			return;
		}

		self::assert_capability();

		check_admin_referer( 'mail_doctor_settings_nonce', 'mail_doctor_settings_nonce' );

		$section          = isset( $_POST['section'] ) ? sanitize_key( wp_unslash( $_POST['section'] ) ) : 'smtp';
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_settings().
		$settings         = isset( $_POST['mail_doctor_settings'] ) && is_array( $_POST['mail_doctor_settings'] ) ? wp_unslash( $_POST['mail_doctor_settings'] ) : array();
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in Profiles::sync_from_form().
		$profiles_payload = isset( $_POST['mail_doctor_profiles'] ) && is_array( $_POST['mail_doctor_profiles'] ) ? wp_unslash( $_POST['mail_doctor_profiles'] ) : array();
		$current          = self::get_settings();

		// Checkbox fields are omitted from POST when unchecked; default them to false before merging.
		// Define which checkboxes belong to which section to avoid overwriting invalid keys.
		$section_checkboxes = array(
			'smtp'         => array( 'force_from_email_lock', 'force_from_name_lock' ),
			'logging'      => array( 'mask_recipients', 'redact_content' ),
			'advanced'     => array( 'fallback_transport', 'debug_logging' ),
		);

		// Flatten the list of all known checkbox keys.
		$all_checkboxes = array();
		foreach ( $section_checkboxes as $keys ) {
			foreach ( $keys as $key ) {
				$all_checkboxes[] = $key;
			}
		}

		// Identify checkboxes relevant to the current section.
		$current_section_keys = isset( $section_checkboxes[ $section ] ) ? $section_checkboxes[ $section ] : array();

		foreach ( $all_checkboxes as $checkbox_key ) {
			// If it's in the current section, missing from POST means unchecked (false).
			if ( in_array( $checkbox_key, $current_section_keys, true ) ) {
				if ( ! isset( $settings[ $checkbox_key ] ) ) {
					$settings[ $checkbox_key ] = false;
				}
			} else {
				// If it belongs to another section, missing from POST means preserve existing (refill).
				if ( ! isset( $settings[ $checkbox_key ] ) ) {
					$settings[ $checkbox_key ] = isset( $current[ $checkbox_key ] ) ? $current[ $checkbox_key ] : false;
				}
			}
		}

		$settings = wp_parse_args( $settings, $current );

		if ( 'profiles' === $section && class_exists( Profiles::class ) ) {
			Profiles::sync_from_form( $profiles_payload );
		}

		$sanitized = self::sanitize_settings( $settings );

		$helper_settings = Settings::all();

		// Helper to set a value, preserving existing engine secrets when the
		// submitted value is intentionally blank for non-selected transports.
		$current_transport = $sanitized['transport'];
		$set_or_preserve   = static function ( array &$target, string $key, $value, ?string $only_when_transport = null ) use ( $current_transport ) {
			$is_string = is_string( $value );
			$is_empty  = ( '' === $value || null === $value );

			// When a specific transport is active, allow explicit clearing.
			if ( null !== $only_when_transport ) {
				if ( $only_when_transport === $current_transport ) {
					$target[ $key ] = $value; // allow empty to clear.
					return;
				}

				// For other transports, do not overwrite with empty values.
				if ( $is_empty ) {
					return;
				}
			}

			// Generic assignment (non-transport-sensitive) or non-empty value.
			if ( ! $is_empty || ! array_key_exists( $key, $target ) ) {
				$target[ $key ] = $value;
			}
		};

		// Core SMTP/identity.
		$helper_settings['transport']                    = $sanitized['transport'];
		$helper_settings['async_mode']                   = $sanitized['async_mode'];
		$helper_settings['fallback_transport']           = $sanitized['fallback_transport'];
		$helper_settings['force_from_email_lock']        = ! empty( $sanitized['force_from_email_lock'] );
		$helper_settings['force_from_name_lock']         = ! empty( $sanitized['force_from_name_lock'] );

		$helper_settings['active_profile']               = Settings::sanitize_profile( $settings['active_profile'] ?? Settings::get_active_profile() );

		$helper_settings['smtp_host']       = $sanitized['host'];
		$helper_settings['smtp_port']       = $sanitized['port'];
		$helper_settings['smtp_encryption'] = $sanitized['encryption'];
		$helper_settings['smtp_username']   = $sanitized['username'];
		$helper_settings['smtp_password']   = $sanitized['password'];
		$helper_settings['password']         = $sanitized['password']; // Mirror alias so get_settings() can read it directly.
		$helper_settings['from_email']      = $sanitized['from_email'];
		$helper_settings['from_name']       = $sanitized['from_name'];
		$helper_settings['debug_logging']   = $sanitized['debug_logging'];

		// Provider credentials (preserve on non-selected transports when blank).
		$set_or_preserve( $helper_settings, 'mailgun_api_key', $sanitized['mailgun_api_key'], 'mailgun_api' );
		$set_or_preserve( $helper_settings, 'mailgun_api_domain', $sanitized['mailgun_api_domain'], 'mailgun_api' );
		$set_or_preserve( $helper_settings, 'mailgun_api_endpoint', $sanitized['mailgun_api_endpoint'], 'mailgun_api' );

		$set_or_preserve( $helper_settings, 'sendgrid_api_key', $sanitized['sendgrid_api_key'], 'sendgrid_api' );

		$set_or_preserve( $helper_settings, 'postmark_api_token', $sanitized['postmark_api_token'], 'postmark_api' );

		$set_or_preserve( $helper_settings, 'sparkpost_api_key', $sanitized['sparkpost_api_key'], 'sparkpost_api' );
		$set_or_preserve( $helper_settings, 'sparkpost_api_endpoint', $sanitized['sparkpost_api_endpoint'], 'sparkpost_api' );

		$set_or_preserve( $helper_settings, 'ses_api_key', $sanitized['ses_api_key'], 'ses_api' );
		$set_or_preserve( $helper_settings, 'ses_api_secret', $sanitized['ses_api_secret'], 'ses_api' );
		$set_or_preserve( $helper_settings, 'ses_api_session_token', $sanitized['ses_api_session_token'], 'ses_api' );
		$set_or_preserve( $helper_settings, 'ses_api_region', $sanitized['ses_api_region'], 'ses_api' );

		$set_or_preserve( $helper_settings, 'generic_api_endpoint', $sanitized['generic_api_endpoint'], 'generic_http' );
		$set_or_preserve( $helper_settings, 'generic_api_method', $sanitized['generic_api_method'], 'generic_http' );
		$set_or_preserve( $helper_settings, 'generic_api_auth_token', $sanitized['generic_api_auth_token'], 'generic_http' );



		update_option( self::OPTION_KEY, $sanitized );

		if ( 'smtp' === $section && class_exists( Profiles::class ) ) {
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Elements sanitized below.
			$profile_request = isset( $_POST['mail_doctor_profile_save'] ) && is_array( $_POST['mail_doctor_profile_save'] ) ? wp_unslash( $_POST['mail_doctor_profile_save'] ) : array();
			$profile_action  = isset( $profile_request['action'] ) ? sanitize_key( $profile_request['action'] ) : '';
			$profile_name    = isset( $profile_request['name'] ) ? sanitize_text_field( $profile_request['name'] ) : '';

			if ( 'save' === $profile_action ) {
				if ( '' === $profile_name ) {
					add_settings_error( 'maildoctor', 'mail_doctor_profile_name_missing', esc_html__( 'Enter a profile name before saving the SMTP settings as a profile.', 'mail-doctor' ), 'error' );
				} elseif ( '' === $sanitized['host'] ) {
					add_settings_error( 'maildoctor', 'mail_doctor_profile_host_missing', esc_html__( 'Provide an SMTP host before saving these settings as a profile.', 'mail-doctor' ), 'error' );
				} else {
					$form = array(
						array(
							'id'         => 0,
							'name'       => $profile_name,
							'host'       => $sanitized['host'],
							'port'       => $sanitized['port'],
							'secure'     => $sanitized['encryption'],
							'auth'       => 'password',
							'username'   => $sanitized['username'],
							'password'   => $sanitized['password'],
							'from_email' => $sanitized['from_email'],
							'from_name'  => $sanitized['from_name'],
							'slug'       => sanitize_key( sanitize_title( $profile_name ) ),
						),
					);

					Profiles::sync_from_form( $form );
					add_settings_error(
						'maildoctor',
						'mail_doctor_profile_created',
						sprintf(
							/* translators: %s profile name. */
							esc_html__( 'Saved the current SMTP settings as "%s".', 'mail-doctor' ),
							esc_html( $profile_name )
						),
						'updated'
					);
				}
			}
		}

		Settings::update( $helper_settings );

		if ( 'woocommerce' === $section && Dependencies::is_woocommerce_available() ) {
			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized in sanitize_woocommerce_toggles().
			$raw_toggles = isset( $_POST['mail_doctor_wc_emails'] ) ? wp_unslash( $_POST['mail_doctor_wc_emails'] ) : array();
			$overrides   = self::sanitize_woocommerce_toggles( $raw_toggles );
			$previous    = Woo::get_toggles();
			if ( $overrides !== $previous ) {
				Woo::save_toggles( $overrides );
			} else {
				// Ensure filters stay registered even if nothing changed.
				Woo::register_email_filters();
			}
		}

		$message = esc_html__( 'Settings saved.', 'mail-doctor' );
		if ( 'woocommerce' === $section ) {
			$message = esc_html__( 'WooCommerce settings saved.', 'mail-doctor' );
		} elseif ( 'profiles' === $section ) {
			$message = esc_html__( 'Profiles updated.', 'mail-doctor' );
		}
		add_settings_error( 'maildoctor', 'mail_doctor_settings_saved', $message, 'updated' );

		$url = self::page_url( 'settings' );

		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Value sanitized via sanitize_key() on next line.
		if ( ! empty( $_POST['section'] ) ) {
			$url = add_query_arg( 'section', sanitize_key( wp_unslash( $_POST['section'] ) ), $url );
		}

		wp_safe_redirect( $url );
		exit;
	}

	/**
	 * Output stored notices.
	 *
	 * @return void
	 */
	public static function render_settings_notices(): void {
		settings_errors( 'maildoctor' );
	}

	/**
	 * Retrieve persistent settings with defaults.
	 *
	 * @return array<string,mixed>
	 */
	public static function get_settings(): array {
		$defaults = array(
			'scope'                        => 'all',
			'from_name'                    => get_bloginfo( 'name' ),
			'from_email'                   => get_option( 'admin_email' ),
			'force_from_email_lock'        => false,
			'force_from_name_lock'         => false,
			'provider'                     => 'generic',
			'transport'                    => 'smtp',
			'host'                         => '',
			'port'                         => 587,
			'encryption'                   => 'tls',
			'auth'                         => 'login',
			'username'                     => '',
			'password'                     => '',
			'mailgun_api_key'              => '',
			'mailgun_api_domain'           => '',
			'mailgun_api_endpoint'         => 'api.mailgun.net',
			'sendgrid_api_key'             => '',
			'postmark_api_token'           => '',
			'sparkpost_api_key'            => '',
			'sparkpost_api_endpoint'       => 'https://api.sparkpost.com',
			'ses_api_key'                  => '',
			'ses_api_secret'               => '',
			'ses_api_session_token'        => '',
			'ses_api_region'               => 'us-east-1',
			'generic_api_endpoint'         => '',
			'generic_api_method'           => 'POST',
			'generic_api_auth_token'       => '',
			'active_profile'               => 'default',
			'max_attempts'                 => 5,
			'cron_active'                  => true,
			'retention_sent'               => 90,
			'retention_failed'             => 30,
			'retention_payload'            => 14,
			'mask_recipients'              => false,
			'redact_content'               => false,
			'preview_email'                => '',
			'preview_order'                => '',

			'async_mode'                   => Settings::async_mode(),
			'fallback_transport'           => Settings::fallback_transport_enabled(),
			'background_sending'           => false,
			'fallback_wp_mail'             => false,
			'debug_logging'                => false,
		);

		$stored = get_option( self::OPTION_KEY, array() );

		if ( ! is_array( $stored ) ) {
			$stored = array();
		}

		if ( isset( $stored['background_sending'] ) && ! isset( $stored['async_mode'] ) ) {
			$stored['async_mode'] = ! empty( $stored['background_sending'] ) ? 'shutdown' : 'sync';
		}

		if ( isset( $stored['fallback_wp_mail'] ) && ! isset( $stored['fallback_transport'] ) ) {
			$stored['fallback_transport'] = ! empty( $stored['fallback_wp_mail'] );
		}

		/**
		 * Filter Mail Doctor settings defaults.
		 *
		 * @since 1.0.0
		 *
		 * @param array<string,mixed> $defaults Default settings.
		 */
		$defaults = apply_filters( 'mail_doctor_settings_defaults', $defaults );

		$settings                       = wp_parse_args( $stored, $defaults );
		$settings['background_sending'] = in_array( $settings['async_mode'], array( 'shutdown', 'action_scheduler' ), true );
		$settings['fallback_wp_mail']   = ! empty( $settings['fallback_transport'] );
		$settings['alerts_threshold']   = $settings['alert_threshold_percent'];
		$settings['alerts_window']      = $settings['alert_window_minutes'];
		$settings['cron_active']        = (bool) wp_next_scheduled( Retry::CRON_HOOK );

		// Bridge the smtp_password → password alias so the admin UI can mask
		// the field and the preserve-on-blank logic in sanitize_settings() works.
		if ( empty( $settings['password'] ) && ! empty( $settings['smtp_password'] ) ) {
			$settings['password'] = $settings['smtp_password'];
		}

		return $settings;
	}

	/**
	 * Sanitize settings payload.
	 *
	 * @param array<string,mixed> $settings Raw settings.
	 * @return array<string,mixed>
	 */
	protected static function sanitize_settings( array $settings ): array {
		$current = self::get_settings();

		$raw_password       = isset( $settings['password'] ) ? (string) $settings['password'] : '';
		$sanitized_password = ( '' === $raw_password || str_contains( $raw_password, '•' ) )
			? $current['password']
			: $raw_password;

		$raw_ses_secret       = isset( $settings['ses_api_secret'] ) ? (string) $settings['ses_api_secret'] : '';
		$sanitized_ses_secret = ( '' === $raw_ses_secret || str_contains( $raw_ses_secret, '•' ) )
			? $current['ses_api_secret']
			: $raw_ses_secret;

		$raw_async_mode = isset( $settings['async_mode'] ) ? sanitize_key( $settings['async_mode'] ) : 'sync';
		$async_choices  = array_keys( Settings::async_mode_choices() );
		if ( ! in_array( $raw_async_mode, $async_choices, true ) ) {
			$raw_async_mode = 'sync';
		}
		if ( 'action_scheduler' === $raw_async_mode && ! Settings::action_scheduler_available() ) {
			$raw_async_mode = 'shutdown';
		}

		$fallback_enabled = ! empty( $settings['fallback_transport'] );



		$sanitized = array(
			'scope'                        => isset( $settings['scope'] ) ? sanitize_key( $settings['scope'] ) : 'all',
			'from_name'                    => isset( $settings['from_name'] ) ? sanitize_text_field( $settings['from_name'] ) : '',
			'from_email'                   => isset( $settings['from_email'] ) ? sanitize_email( $settings['from_email'] ) : '',
			'provider'                     => isset( $settings['provider'] ) ? sanitize_key( $settings['provider'] ) : 'generic',
			'transport'                    => isset( $settings['transport'] ) ? sanitize_key( $settings['transport'] ) : 'smtp',
			'host'                         => isset( $settings['host'] ) ? sanitize_text_field( $settings['host'] ) : '',
			'port'                         => isset( $settings['port'] ) ? max( 1, absint( $settings['port'] ) ) : 587,
			'encryption'                   => isset( $settings['encryption'] ) ? sanitize_key( $settings['encryption'] ) : 'tls',
			'auth'                         => isset( $settings['auth'] ) ? sanitize_key( $settings['auth'] ) : 'login',
			'username'                     => isset( $settings['username'] ) ? sanitize_text_field( $settings['username'] ) : '',
			'password'                     => $sanitized_password,
			'force_from_email_lock'        => ! empty( $settings['force_from_email_lock'] ),
			'force_from_name_lock'         => ! empty( $settings['force_from_name_lock'] ),
			'mailgun_api_key'              => isset( $settings['mailgun_api_key'] ) ? trim( (string) $settings['mailgun_api_key'] ) : '',
			'mailgun_api_domain'           => isset( $settings['mailgun_api_domain'] ) ? sanitize_text_field( $settings['mailgun_api_domain'] ) : '',
			'mailgun_api_endpoint'         => isset( $settings['mailgun_api_endpoint'] ) ? sanitize_text_field( $settings['mailgun_api_endpoint'] ) : 'api.mailgun.net',
			'sendgrid_api_key'             => isset( $settings['sendgrid_api_key'] ) ? trim( (string) $settings['sendgrid_api_key'] ) : '',
			'postmark_api_token'           => isset( $settings['postmark_api_token'] ) ? trim( (string) $settings['postmark_api_token'] ) : '',
			'sparkpost_api_key'            => isset( $settings['sparkpost_api_key'] ) ? trim( (string) $settings['sparkpost_api_key'] ) : '',
			'sparkpost_api_endpoint'       => isset( $settings['sparkpost_api_endpoint'] ) ? sanitize_text_field( $settings['sparkpost_api_endpoint'] ) : 'https://api.sparkpost.com',
			'ses_api_key'                  => isset( $settings['ses_api_key'] ) ? trim( (string) $settings['ses_api_key'] ) : '',
			'ses_api_secret'               => $sanitized_ses_secret,
			'ses_api_session_token'        => isset( $settings['ses_api_session_token'] ) ? trim( (string) $settings['ses_api_session_token'] ) : '',
			'ses_api_region'               => isset( $settings['ses_api_region'] ) ? sanitize_text_field( $settings['ses_api_region'] ) : 'us-east-1',
			'generic_api_endpoint'         => isset( $settings['generic_api_endpoint'] ) ? esc_url_raw( $settings['generic_api_endpoint'] ) : '',
			'generic_api_method'           => isset( $settings['generic_api_method'] ) ? strtoupper( sanitize_text_field( $settings['generic_api_method'] ) ) : 'POST',
			'generic_api_auth_token'       => isset( $settings['generic_api_auth_token'] ) ? sanitize_text_field( $settings['generic_api_auth_token'] ) : '',
			'max_attempts'                 => isset( $settings['max_attempts'] ) ? max( 1, absint( $settings['max_attempts'] ) ) : 5,
			'retention_sent'               => isset( $settings['retention_sent'] ) ? max( 1, absint( $settings['retention_sent'] ) ) : 90,
			'retention_failed'             => isset( $settings['retention_failed'] ) ? max( 1, absint( $settings['retention_failed'] ) ) : 30,
			'retention_payload'            => isset( $settings['retention_payload'] ) ? max( 1, absint( $settings['retention_payload'] ) ) : 14,
			'mask_recipients'              => ! empty( $settings['mask_recipients'] ),
			'redact_content'               => ! empty( $settings['redact_content'] ),
			'preview_email'                => isset( $settings['preview_email'] ) ? sanitize_text_field( $settings['preview_email'] ) : '',
			'preview_order'                => isset( $settings['preview_order'] ) ? sanitize_text_field( $settings['preview_order'] ) : '',

			'async_mode'                   => $raw_async_mode,
			'background_sending'           => in_array( $raw_async_mode, array( 'shutdown', 'action_scheduler' ), true ),
			'fallback_transport'           => $fallback_enabled,
			'fallback_wp_mail'             => $fallback_enabled,
			'debug_logging'                => ! empty( $settings['debug_logging'] ),
		);

		$allowed_transports = array_keys( self::get_transport_options() );
		if ( ! in_array( $sanitized['transport'], $allowed_transports, true ) ) {
			$sanitized['transport'] = 'smtp';
		}

		switch ( $sanitized['transport'] ) {
			case 'smtp':
				break;
			default:
				$sanitized['host']       = '';
				$sanitized['username']   = '';
				$sanitized['password']   = '';
				$sanitized['auth']       = 'login';
				$sanitized['encryption'] = 'none';
		}

		if ( 'mailgun_api' !== $sanitized['transport'] ) {
			$sanitized['mailgun_api_key']      = '';
			$sanitized['mailgun_api_domain']   = '';
			$sanitized['mailgun_api_endpoint'] = 'api.mailgun.net';
		}

		if ( 'sendgrid_api' !== $sanitized['transport'] ) {
			$sanitized['sendgrid_api_key'] = '';
		}

		if ( 'postmark_api' !== $sanitized['transport'] ) {
			$sanitized['postmark_api_token'] = '';
		}

		if ( 'sparkpost_api' !== $sanitized['transport'] ) {
			$sanitized['sparkpost_api_key']      = '';
			$sanitized['sparkpost_api_endpoint'] = 'https://api.sparkpost.com';
		}

		if ( 'ses_api' !== $sanitized['transport'] ) {
			$sanitized['ses_api_key']           = '';
			$sanitized['ses_api_secret']        = '';
			$sanitized['ses_api_session_token'] = '';
		}

		if ( 'generic_http' !== $sanitized['transport'] ) {
			$sanitized['generic_api_endpoint']   = '';
			$sanitized['generic_api_method']     = 'POST';
			$sanitized['generic_api_auth_token'] = '';
		}

		if ( ! in_array( $sanitized['generic_api_method'], array( 'POST', 'PUT' ), true ) ) {
			$sanitized['generic_api_method'] = 'POST';
		}

		$regions = array_keys( self::get_ses_regions() );
		if ( ! in_array( $sanitized['ses_api_region'], $regions, true ) ) {
			$sanitized['ses_api_region'] = 'us-east-1';
		}

		$sanitized['active_profile'] = Settings::sanitize_profile( $settings['active_profile'] ?? Settings::get_active_profile() );

		/**
		 * Filter sanitized Mail Doctor settings prior to persistence.
		 *
		 * @since 1.0.0
		 *
		 * @param array<string,mixed> $sanitized Sanitized values.
		 * @param array<string,mixed> $settings  Raw submitted values.
		 */
		return apply_filters( 'mail_doctor_settings_sanitized', $sanitized, $settings );
	}



	/**
	 * Provider preset options.
	 *
	 * @return array<string,string>
	 */
	protected static function get_provider_options(): array {
		return array(
			'generic'  => esc_html__( 'Generic SMTP', 'mail-doctor' ),
			'gmail'    => esc_html__( 'Gmail / Google Workspace', 'mail-doctor' ),
			'mailgun'  => esc_html__( 'Mailgun', 'mail-doctor' ),
			'ses'      => esc_html__( 'Amazon SES', 'mail-doctor' ),
		);
	}

	/**
	 * Transport options exposed in the delivery method dropdown.
	 *
	 * @return array<string,string>
	 */
	public static function get_transport_options(): array {
		return array(
			'smtp'          => esc_html__( 'SMTP', 'mail-doctor' ),
			'mailgun_api'   => esc_html__( 'Mailgun REST API', 'mail-doctor' ),
			'sendgrid_api'  => esc_html__( 'SendGrid Web API', 'mail-doctor' ),
			'postmark_api'  => esc_html__( 'Postmark API', 'mail-doctor' ),
			'sparkpost_api' => esc_html__( 'SparkPost API', 'mail-doctor' ),
			'ses_api'       => esc_html__( 'Amazon SES API', 'mail-doctor' ),
			'generic_http'  => esc_html__( 'Generic HTTP Endpoint', 'mail-doctor' ),
		);
	}

	/**
	 * List of supported Amazon SES regions.
	 *
	 * @return array<string,string>
	 */
	public static function get_ses_regions(): array {
		return array(
			'us-east-1'      => esc_html__( 'US East (N. Virginia)', 'mail-doctor' ),
			'us-east-2'      => esc_html__( 'US East (Ohio)', 'mail-doctor' ),
			'us-west-2'      => esc_html__( 'US West (Oregon)', 'mail-doctor' ),
			'ca-central-1'   => esc_html__( 'Canada (Central)', 'mail-doctor' ),
			'eu-west-1'      => esc_html__( 'Europe (Ireland)', 'mail-doctor' ),
			'eu-west-2'      => esc_html__( 'Europe (London)', 'mail-doctor' ),
			'eu-central-1'   => esc_html__( 'Europe (Frankfurt)', 'mail-doctor' ),
			'eu-central-2'   => esc_html__( 'Europe (Zurich)', 'mail-doctor' ),
			'ap-south-1'     => esc_html__( 'Asia Pacific (Mumbai)', 'mail-doctor' ),
			'ap-southeast-1' => esc_html__( 'Asia Pacific (Singapore)', 'mail-doctor' ),
			'ap-southeast-2' => esc_html__( 'Asia Pacific (Sydney)', 'mail-doctor' ),
			'ap-northeast-1' => esc_html__( 'Asia Pacific (Tokyo)', 'mail-doctor' ),
			'ap-northeast-2' => esc_html__( 'Asia Pacific (Seoul)', 'mail-doctor' ),
			'sa-east-1'      => esc_html__( 'South America (São Paulo)', 'mail-doctor' ),
		);
	}



	/**
	 * Format a timestamp for admin display using site preferences.
	 *
	 * @param int $timestamp Timestamp.
	 * @return string
	 */
	protected static function format_admin_datetime( int $timestamp ): string {
		if ( $timestamp <= 0 ) {
			return '';
		}

		$date_format = get_option( 'date_format' );
		$time_format = get_option( 'time_format' );

		return wp_date( $date_format . ' ' . $time_format, $timestamp );
	}

	/**
	 * Format a timestamp into a human relative string.
	 *
	 * @param int $timestamp Timestamp.
	 * @return string
	 */
	protected static function format_relative_time( int $timestamp ): string {
		if ( $timestamp <= 0 ) {
			return '';
		}

		$now = current_time( 'timestamp' );

		if ( $timestamp >= $now ) {
			return esc_html__( 'Just now', 'mail-doctor' );
		}

		/* translators: %s: human-readable time difference. */
		return sprintf( esc_html__( '%s ago', 'mail-doctor' ), human_time_diff( $timestamp, $now ) );
	}

	/**
	 * Sanitize WooCommerce toggle submission.
	 *
	 * @param mixed $raw Raw toggle payload.
	 * @return array<string,bool>
	 */
	protected static function sanitize_woocommerce_toggles( $raw ): array {
		if ( ! Dependencies::is_woocommerce_available() ) {
			return array();
		}

		$payload = array();
		if ( is_array( $raw ) ) {
			foreach ( $raw as $email_id => $value ) {
				$key             = sanitize_text_field( (string) $email_id );
				$payload[ $key ] = ! empty( $value );
			}
		}

		$overrides = array();
		foreach ( Woo::get_email_toggle_data() as $email ) {
			$id        = $email['id'];
			$requested = array_key_exists( $id, $payload ) ? (bool) $payload[ $id ] : (bool) $email['default_enabled'];

			if ( $requested !== (bool) $email['default_enabled'] ) {
				$overrides[ $id ] = $requested;
			}
		}

		return $overrides;
	}
}
