<?php
/**
 * SMTP mailer integration.
 *
 * @package SubmissionInbox
 */

namespace SUBIN\Mailer;

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

/**
 * Configures WordPress PHPMailer from plugin settings.
 */
class SmtpMailer {
	/**
	 * Settings repository.
	 *
	 * @var \SUBIN_SettingsRepository
	 */
	private $settings;

	/**
	 * Constructor.
	 *
	 * @param \SUBIN_SettingsRepository $settings Settings repository.
	 */
	public function __construct( \SUBIN_SettingsRepository $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function register() {
		add_filter( 'wp_mail_from', array( $this, 'filter_from_email' ) );
		add_filter( 'wp_mail_from_name', array( $this, 'filter_from_name' ) );
		add_action( 'phpmailer_init', array( $this, 'configure' ) );
	}

	/**
	 * Apply the configured sender email to all WordPress mail.
	 *
	 * @param string $from_email Existing From email.
	 * @return string
	 */
	public function filter_from_email( $from_email ) {
		return $this->resolve_from_email( (string) $from_email );
	}

	/**
	 * Apply the configured sender name to all WordPress mail.
	 *
	 * @param string $from_name Existing From name.
	 * @return string
	 */
	public function filter_from_name( $from_name ) {
		$settings = $this->settings->all();
		$name     = sanitize_text_field( (string) ( $settings['from_name'] ?? '' ) );

		return '' !== $name ? $name : sanitize_text_field( (string) $from_name );
	}

	/**
	 * Configure PHPMailer for SMTP when enabled and sufficiently configured.
	 *
	 * @param object $phpmailer WordPress PHPMailer instance.
	 * @return void
	 */
	public function configure( $phpmailer ) {
		$settings = $this->settings->all();

		if ( ! is_object( $phpmailer ) ) {
			return;
		}

		// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- PHPMailer exposes public properties with upstream camel-case names.
		if ( property_exists( $phpmailer, 'Timeout' ) ) {
			$phpmailer->Timeout = absint( apply_filters( 'subin_smtp_timeout', 8 ) );
		}

		$from_email = $this->resolve_from_email( isset( $phpmailer->From ) ? (string) $phpmailer->From : '' );
		if ( '' !== $from_email && method_exists( $phpmailer, 'setFrom' ) ) {
			$from_name = $this->filter_from_name( isset( $phpmailer->FromName ) ? (string) $phpmailer->FromName : '' );
			try {
				$phpmailer->setFrom( $from_email, $from_name, false );
			} catch ( \Exception $exception ) {
				unset( $exception );
			}
		}

		if ( empty( $settings['enable_smtp'] ) || empty( $settings['smtp_host'] ) ) {
			return;
		}

		if ( ! method_exists( $phpmailer, 'isSMTP' ) ) {
			return;
		}

		$phpmailer->isSMTP();
		$phpmailer->Host       = (string) $settings['smtp_host'];
		$port                  = absint( $settings['smtp_port'] );
		$phpmailer->Port       = $port > 0 ? $port : 587;
		$phpmailer->SMTPAuth   = (bool) $settings['smtp_auth'];
		$phpmailer->Username   = (string) $settings['smtp_username'];
		$phpmailer->Password   = (string) $settings['smtp_password'];
		$phpmailer->SMTPSecure = $this->get_smtp_secure( (string) $settings['smtp_encryption'] );
		// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
	}

	/**
	 * Resolve a safe From email without falling back to wordpress@localhost.
	 *
	 * @param string $current Current From email.
	 * @return string
	 */
	private function resolve_from_email( $current = '' ) {
		$settings = $this->settings->all();
		$from     = sanitize_email( (string) ( $settings['from_email'] ?? '' ) );

		if ( '' !== $from && is_email( $from ) ) {
			return $from;
		}

		$admin_email = sanitize_email( (string) get_option( 'admin_email' ) );
		if ( '' !== $admin_email && is_email( $admin_email ) ) {
			return $admin_email;
		}

		$current = sanitize_email( (string) $current );
		if ( '' !== $current && is_email( $current ) && 'wordpress@localhost' !== strtolower( $current ) ) {
			return $current;
		}

		return '';
	}

	/**
	 * Map setting value to PHPMailer SMTP secure value.
	 *
	 * @param string $encryption Encryption setting.
	 * @return string
	 */
	private function get_smtp_secure( $encryption ) {
		if ( 'tls' === $encryption ) {
			return 'tls';
		}

		if ( 'ssl' === $encryption ) {
			return 'ssl';
		}

		return '';
	}
}
