<?php
/**
 * @package Hafenstudios\Core
 */

namespace Hafenstudios\Core\Mail\Driver;

use Hafenstudios\Core\Mail\MailDriver;
use Hafenstudios\Core\Mail\Message;

defined( 'ABSPATH' ) || exit;

/**
 * SMTP-Treiber. Konfiguriert PHPMailer ueber den `phpmailer_init`-Hook und nutzt
 * ansonsten wp_mail() als Transportweg, damit Themes/Plugins-Filter erhalten
 * bleiben.
 *
 * @phpstan-type SmtpConfig array{host:string,port:int,encryption:string,auth:bool,username:string,password:string,from_email:string,from_name:string}
 */
final class SmtpDriver implements MailDriver {

	/**
	 * @var array<string, mixed>
	 */
	private array $config;

	/**
	 * @param array<string, mixed> $config SMTP-Zugangsdaten.
	 */
	public function __construct( array $config ) {
		$this->config = $config;
	}

	public function key(): string {
		return 'smtp';
	}

	public function send( Message $message ): bool {
		$alt       = $message->is_html ? $message->text_body : '';
		$configure = function ( $phpmailer ) use ( $alt ) {
			$phpmailer->isSMTP();
			$phpmailer->Host       = (string) ( $this->config['host'] ?? '' );
			$phpmailer->Port       = (int) ( $this->config['port'] ?? 587 );
			$encryption            = (string) ( $this->config['encryption'] ?? 'tls' );
			$phpmailer->SMTPSecure = in_array( $encryption, array( 'tls', 'ssl' ), true ) ? $encryption : '';
			$phpmailer->SMTPAuth   = ! empty( $this->config['auth'] );
			if ( $phpmailer->SMTPAuth ) {
				$phpmailer->Username = (string) ( $this->config['username'] ?? '' );
				$phpmailer->Password = (string) ( $this->config['password'] ?? '' );
			}
			// Multipart-Alternative (Zustellbarkeit): nur, wenn ein Klartext-Body
			// vorliegt. Der Hook ist ohnehin auf diese Mail begrenzt (add/remove
			// um den wp_mail-Aufruf), daher kein Global-Leak.
			if ( '' !== $alt ) {
				$phpmailer->AltBody = $alt;
			}
		};

		add_action( 'phpmailer_init', $configure, 20 );
		$ok = wp_mail( $message->to, $message->subject, $message->body, $message->build_headers() );
		remove_action( 'phpmailer_init', $configure, 20 );

		return $ok;
	}
}
