<?php
/**
 * Mailer configuration helpers.
 *
 * @package MailDoctor
 */

namespace MailDoctor;

use PHPMailer\PHPMailer\PHPMailer;

trait Mailer_Config_Trait {

	/**
	 * Configure PHPMailer to use SMTP transport.
	 *
	 * @param PHPMailer $phpmailer Mailer instance.
	 * @return void
	 */
	public static function configure( PHPMailer $phpmailer ): void {
		self::configure_mailer( $phpmailer, false );
	}

	/**
	 * Apply SMTP configuration to a PHPMailer instance.
	 *
	 * @param PHPMailer $phpmailer Mailer instance.
	 * @param bool      $force     Force configuration regardless of scope rules.
	 * @return bool True when configuration applied.
	 */
	public static function configure_mailer( PHPMailer $phpmailer, bool $force = false ): bool {
		if ( self::$bypass_plugin ) {
			self::debug_log( 'configure_mailer skipped: bypass' );
			return false;
		}

		$settings = Settings::all();

		if ( 'mail' === ( $settings['transport'] ?? '' ) ) {
			self::debug_log( 'configure_mailer skipped: default PHP Mail transport active' );
			return false;
		}

		if ( ! $force && ! self::$force_override && ! self::$should_override && 'all' !== $settings['override_scope'] ) {
			self::debug_log(
				'configure_mailer skipped: scope rules',
				array(
					'force'           => $force,
					'should_override' => self::$should_override,
				)
			);
			return false;
		}

		self::prepare_profile();

		$credentials = self::$active_profile;
		self::debug_log(
			'configure_mailer credentials',
			array(
				'profile'      => self::$active_profile_key,
				'host'         => $credentials['host'] ?? '',
				'port'         => $credentials['port'] ?? '',
				'auth'         => $credentials['auth'] ?? '',
				'encryption'   => $credentials['encryption'] ?? '',
				'username'     => $credentials['username'] ?? '',
				'password_len' => strlen( (string) ( $credentials['password'] ?? '' ) ),
				'password_pfx' => mb_substr( (string) ( $credentials['password'] ?? '' ), 0, 3 ),
			)
		);

		if ( isset( $credentials['auth'] ) && 'oauth2' === $credentials['auth'] && class_exists( __NAMESPACE__ . '\OAuth' ) ) {
			$credentials          = OAuth::ensure_credentials( $credentials );
			self::$active_profile = $credentials;
		}

		if ( empty( $credentials['host'] ) ) {
			self::debug_log( 'configure_mailer failed: missing host', array( 'profile' => self::$active_profile_key ) );
			return false;
		}

		$encryption = $credentials['encryption'] ?? 'tls';

		$phpmailer->isSMTP();
		$phpmailer->Host        = $credentials['host'];
		$phpmailer->Port        = (int) ( $credentials['port'] ?? 587 );
		$phpmailer->SMTPAutoTLS = ( 'none' !== $encryption );

		if ( 'ssl' === $encryption ) {
			$phpmailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
		} elseif ( 'tls' === $encryption ) {
			$phpmailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
		} else {
			$phpmailer->SMTPSecure = '';
		}

		if ( isset( $credentials['auth'] ) && 'oauth2' === $credentials['auth'] ) {
			if ( empty( $credentials['username'] ) ) {
				self::debug_log( 'configure_mailer failed: oauth2 missing username', array( 'profile' => self::$active_profile_key ) );
				return false;
			}

			$token = $credentials['secret']['access_token'] ?? '';

			if ( ! $token ) {
				self::debug_log( 'configure_mailer failed: oauth2 missing access token', array( 'profile' => self::$active_profile_key ) );
				return false;
			}

			$phpmailer->SMTPAuth = true;
			$phpmailer->AuthType = 'XOAUTH2';
			$phpmailer->Username = $credentials['username'];
			$phpmailer->oauth    = new OAuthTokenCredential( $credentials['username'], $token );
		} else {
			$smtp_username = $credentials['username'] ?? '';
			
			// Fallback to from_email if provider is a preset requiring authentication but username was left blank
			if ( empty( $smtp_username ) && in_array( $settings['provider'] ?? '', array( 'brevo', 'gmail', 'outlook' ), true ) ) {
				$smtp_username = self::resolve_from_email();
				self::debug_log( 'configure_mailer fallback username', array( 'username' => $smtp_username ) );
			}

			$phpmailer->SMTPAuth = ! empty( $smtp_username );

			if ( $phpmailer->SMTPAuth ) {
				$phpmailer->Username = $smtp_username;
				$phpmailer->Password = ! empty( $credentials['password'] )
					? $credentials['password']
					: ( $credentials['secret']['password'] ?? '' );
				$phpmailer->AuthType = 'LOGIN';
			}
		}

		$phpmailer->setFrom( self::resolve_from_email(), self::resolve_from_name(), false );
		self::debug_log(
			'configure_mailer applied',
			array(
				'host'     => $phpmailer->Host,
				'port'     => $phpmailer->Port,
				'secure'   => $phpmailer->SMTPSecure,
				'authtype' => $phpmailer->AuthType,
				'username' => $phpmailer->Username,
				'autotls'  => $phpmailer->SMTPAutoTLS,
			)
		);

		if ( ! empty( self::$thread_headers['message_id'] ) ) {
			$phpmailer->MessageID = self::$thread_headers['message_id'];
		}

		if ( ! empty( self::$thread_headers['in_reply_to'] ) ) {
			$phpmailer->addCustomHeader( 'In-Reply-To', self::$thread_headers['in_reply_to'] );
			$phpmailer->addCustomHeader( 'References', self::$thread_headers['in_reply_to'] );
		}

		return true;
	}

	/**
	 * Ensure wp_mail_from is valid.
	 *
	 * @param string $from Original from email.
	 * @return string
	 */
	public static function filter_from_email( string $from ): string {
		if ( self::$bypass_plugin ) {
			return $from;
		}

		$settings = Settings::all();
		$lock     = ! empty( $settings['force_from_email_lock'] );
		$resolved = self::resolve_from_email();

		if ( self::$should_override || self::$force_override || $lock ) {
			return $resolved ?: $from;
		}

		if ( empty( $from ) || ! is_email( $from ) ) {
			return $resolved ?: $from;
		}

		return $from;
	}

	/**
	 * Ensure wp_mail_from_name always populated.
	 *
	 * @param string $name Original name.
	 * @return string
	 */
	public static function filter_from_name( string $name ): string {
		if ( self::$bypass_plugin ) {
			return $name;
		}

		$settings = Settings::all();
		$lock     = ! empty( $settings['force_from_name_lock'] );
		$resolved = self::resolve_from_name();

		if ( self::$should_override || self::$force_override || $lock ) {
			return $resolved ?: $name;
		}

		if ( '' === trim( $name ) ) {
			return $resolved ?: $name;
		}

		return $name;
	}

	/**
	 * Ensure PHPMailer classes are loaded.
	 *
	 * @return void
	 */
	public static function ensure_phpmailer_loaded(): void {
		if ( ! class_exists( '\PHPMailer\PHPMailer\PHPMailer', false ) ) {
			require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
			require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
			require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
		}
	}

	/**
	 * Execute a raw connection test without firing wp_mail hooks.
	 *
	 * @return array<string, mixed>
	 */
	public static function test_connection(): array {
		$result = array(
			'success' => false,
			'message' => __( 'SMTP settings are incomplete.', 'mail-doctor' ),
			'data'    => array(),
		);

		self::ensure_phpmailer_loaded();

		$phpmailer = new PHPMailer( true );
		$debug_log = array();

		$phpmailer->SMTPDebug   = 2;
		$phpmailer->Debugoutput = static function ( $message, $level ) use ( &$debug_log ) {
			$message = is_string( $message ) ? trim( $message ) : '';
			if ( '' === $message ) {
				return;
			}

			$debug_log[] = sprintf( '[%d] %s', (int) $level, $message );
		};

		if ( ! self::configure_mailer( $phpmailer, true ) ) {
			if ( ! empty( $debug_log ) ) {
				$result['data']['debug'] = $debug_log;
			}
			return $result;
		}

		try {
			$connected = $phpmailer->smtpConnect();
			if ( $connected ) {
				$result['success'] = true;
				$result['message'] = __( 'Connection successful. SMTP server is reachable. Use "Send Test Email" to verify credentials.', 'mail-doctor' );
			} else {
				$result['message'] = __( 'Unable to open SMTP connection. Verify host, port, and firewall rules.', 'mail-doctor' );
			}

			$result['data'] = array(
				'host'       => $phpmailer->Host,
				'port'       => $phpmailer->Port,
				'encryption' => $phpmailer->SMTPSecure ?: __( 'None', 'mail-doctor' ),
				'auth'       => $phpmailer->SMTPAuth,
				'debug'      => $debug_log,
			);
		} catch ( \Throwable $throwable ) {
			$result['message'] = $throwable->getMessage();
			if ( ! empty( $debug_log ) ) {
				$result['data']['debug'] = $debug_log;
			}
		}

		try {
			$phpmailer->smtpClose();
		} catch ( \Throwable $close_err ) {
			// Ignore close errors.
		}

		return $result;
	}


}
