<?php
/**
 * Validation, sanitization, and utilities for Email Delivery (SMTP).
 *
 * @package EmailSmtp
 * @since 1.0.1
 */

namespace EmailSmtp\Includes;

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

use EmailSmtp\Module;
use WP_PowerSuite\Core\OptionStoreModuleSettingsRepository;

final class SmtpSettingsHelper {

	/**
	 * @return array<string, mixed>
	 */
	public static function getDefaults(): array {
		return [
			'smtp_host'        => '',
			'smtp_port'        => '587',
			'smtp_encryption'  => 'tls',
			'smtp_auth'        => '1',
			'smtp_username'    => '',
			'smtp_password'    => '',
			'from_email'       => get_option( 'admin_email' ),
			'from_name'        => get_option( 'blogname' ),
			'reply_to_email'   => '',
			'reply_to_name'    => '',
			'return_path'      => '',
			'override_from'    => '1',
			'smtp_debug'       => '0',
		];
	}

	/**
	 * Sanitize and validate module settings before save.
	 *
	 * @param array<string, mixed> $settings Raw settings.
	 * @return array<string, mixed>
	 */
	public static function normalizeSettings( array $settings ): array {
		$defaults = self::getDefaults();
		$settings = array_merge( $defaults, $settings );

		$settings['smtp_host'] = self::sanitizeHost( (string) ( $settings['smtp_host'] ?? '' ) );
		$settings['smtp_port'] = (string) max( 1, min( 65535, (int) ( $settings['smtp_port'] ?? 587 ) ) );

		$encryption = sanitize_key( (string) ( $settings['smtp_encryption'] ?? 'tls' ) );
		$settings['smtp_encryption'] = in_array( $encryption, [ 'tls', 'ssl', '' ], true ) ? $encryption : 'tls';

		$settings['smtp_auth']       = ! empty( $settings['smtp_auth'] ) && $settings['smtp_auth'] !== '0' ? '1' : '0';
		$settings['smtp_username']   = sanitize_text_field( (string) ( $settings['smtp_username'] ?? '' ) );
		$settings['override_from']   = ! empty( $settings['override_from'] ) && $settings['override_from'] !== '0' ? '1' : '0';
		$settings['smtp_debug']      = in_array( (string) ( $settings['smtp_debug'] ?? '0' ), [ '0', '1', '2' ], true )
			? (string) $settings['smtp_debug']
			: '0';

		$from_email = sanitize_email( (string) ( $settings['from_email'] ?? '' ) );
		$settings['from_email'] = is_email( $from_email ) ? $from_email : sanitize_email( (string) $defaults['from_email'] );

		$settings['from_name'] = self::sanitizeFromName( (string) ( $settings['from_name'] ?? '' ) );

		$reply_to = sanitize_email( (string) ( $settings['reply_to_email'] ?? '' ) );
		$settings['reply_to_email'] = is_email( $reply_to ) ? $reply_to : '';

		$settings['reply_to_name'] = self::sanitizeFromName( (string) ( $settings['reply_to_name'] ?? '' ) );

		$return_path = sanitize_email( (string) ( $settings['return_path'] ?? '' ) );
		$settings['return_path'] = is_email( $return_path ) ? $return_path : '';

		return $settings;
	}

	public static function sanitizeHost( string $host ): string {
		$host = strtolower( trim( $host ) );
		if ( $host === '' ) {
			return '';
		}

		// Strip scheme/path if pasted from a URL.
		$host = preg_replace( '#^[a-z]+://#', '', $host ) ?? $host;
		$host = preg_replace( '#/.*$#', '', $host ) ?? $host;

		if ( ! preg_match( '/^[a-z0-9]([a-z0-9.-]*[a-z0-9])?$/i', $host ) ) {
			return '';
		}

		return sanitize_text_field( $host );
	}

	public static function sanitizeFromName( string $name ): string {
		$name = sanitize_text_field( $name );
		if ( function_exists( 'mb_substr' ) ) {
			return mb_substr( $name, 0, 200 );
		}
		return substr( $name, 0, 200 );
	}

	public static function isStoredPasswordEncrypted( string $value ): bool {
		return str_starts_with( $value, 'ENC2:' ) || str_starts_with( $value, 'ENC:' );
	}

	/**
	 * Re-encrypt legacy plaintext or ENC v1 passwords to ENC2 when possible.
	 */
	public static function migrateStoredPassword( string $stored, callable $encrypt ): string {
		if ( $stored === '' ) {
			return '';
		}
		if ( str_starts_with( $stored, 'ENC2:' ) ) {
			return $stored;
		}

		$plain = \EmailSmtp\Module::decryptPasswordStatic( $stored );
		if ( $plain === '' ) {
			return $stored;
		}

		$encrypted = $encrypt( $plain );
		return $encrypted !== '' ? $encrypted : $stored;
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function redactForResponse( array $settings ): array {
		if ( ! empty( $settings['smtp_password'] ) ) {
			$settings['smtp_password'] = \EmailSmtp\Module::getPasswordMask();
		}
		return $settings;
	}

	/**
	 * Detect other active SMTP/mail plugins that may conflict.
	 *
	 * @return list<string> Human-readable plugin names.
	 */
	public static function detectConflictingPlugins(): array {
		if ( ! function_exists( 'is_plugin_active' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		$conflicts = [
			'wp-mail-smtp/wp_mail_smtp.php'         => 'WP Mail SMTP',
			'fluent-smtp/fluent-smtp.php'           => 'FluentSMTP',
			'post-smtp/postman-smtp.php'            => 'Post SMTP',
			'easy-wp-smtp/easy-wp-smtp.php'         => 'Easy WP SMTP',
			'smtp-mailer/main.php'                  => 'SMTP Mailer',
			'wp-smtp/wp-smtp.php'                   => 'WP SMTP',
			'gmail-smtp/main.php'                   => 'Gmail SMTP',
		];

		$found = [];
		foreach ( $conflicts as $plugin_file => $label ) {
			if ( is_plugin_active( $plugin_file ) ) {
				$found[] = $label;
			}
		}

		return $found;
	}

	/**
	 * Deliverability hint when From domain differs from SMTP username domain.
	 *
	 * @param array<string, mixed> $settings
	 */
	public static function getDeliverabilityWarning( array $settings ): string {
		$from      = (string) ( $settings['from_email'] ?? '' );
		$username  = (string) ( $settings['smtp_username'] ?? '' );
		if ( ! is_email( $from ) || ! is_email( $username ) ) {
			return '';
		}

		$from_domain = substr( strrchr( $from, '@' ), 1 );
		$user_domain = substr( strrchr( $username, '@' ), 1 );
		if ( $from_domain === '' || $user_domain === '' || strcasecmp( $from_domain, $user_domain ) === 0 ) {
			return '';
		}

		return sprintf(
			/* translators: 1: From email domain, 2: SMTP username domain */
			__( 'Your From address uses %1$s but SMTP authentication uses %2$s. Align these domains (and verify SPF/DKIM/DMARC) for better deliverability.', 'wp-powersuite' ),
			$from_domain,
			$user_domain
		);
	}

	/**
	 * @param array<string, mixed> $settings
	 * @return array<string, mixed>
	 */
	public static function mergeWithDefaults( array $settings ): array {
		return array_merge( self::getDefaults(), $settings );
	}

	/**
	 * Register wp_mail filter once (also invoked from {@see registerPhpMailerHook()}).
	 */
	public static function registerWpMailFilter(): void {
		if ( ! has_filter( 'wp_mail', [ self::class, 'filterWpMailArgs' ] ) ) {
			add_filter( 'wp_mail', [ self::class, 'filterWpMailArgs' ], 5, 1 );
		}
	}

	/**
	 * Apply SMTP identity headers and ensure transport hook is registered for every wp_mail call.
	 *
	 * @param array<string, mixed> $args wp_mail arguments.
	 * @return array<string, mixed>
	 */
	public static function filterWpMailArgs( array $args ): array {
		if ( apply_filters( 'wp_powersuite_skip_smtp_mail_args', false, $args ) ) {
			return $args;
		}
		if ( ! class_exists( OptionStoreModuleSettingsRepository::class ) ) {
			return $args;
		}
		if ( ! OptionStoreModuleSettingsRepository::isModuleEnabled( 'email-smtp' ) ) {
			return $args;
		}

		self::ensureModuleLoaded();
		if ( class_exists( Module::class ) ) {
			Module::registerPhpMailerHook();
		}

		$headers = $args['headers'] ?? [];
		if ( is_string( $headers ) ) {
			$headers = array_filter( array_map( 'trim', explode( "\n", $headers ) ) );
		}
		if ( ! is_array( $headers ) ) {
			$headers = [];
		}

		$args['headers'] = self::appendIdentityHeaders( $headers );

		return $args;
	}

	/**
	 * Ensure SMTP transport is registered and apply configured From / Reply-To headers.
	 *
	 * @param array<int, string> $headers Existing wp_mail headers.
	 * @return array<int, string>
	 */
	public static function prepareOutgoingMailHeaders( array $headers ): array {
		if ( ! class_exists( OptionStoreModuleSettingsRepository::class ) ) {
			return $headers;
		}
		if ( ! OptionStoreModuleSettingsRepository::isModuleEnabled( 'email-smtp' ) ) {
			return $headers;
		}

		self::ensureModuleLoaded();
		if ( class_exists( Module::class ) ) {
			Module::registerPhpMailerHook();
		}

		return self::appendIdentityHeaders( $headers );
	}

	/**
	 * @param array<int, string> $headers
	 * @return array<int, string>
	 */
	public static function appendIdentityHeaders( array $headers ): array {
		$settings = OptionStoreModuleSettingsRepository::forModule( 'email-smtp' )->all( [] );
		$settings = self::mergeWithDefaults( is_array( $settings ) ? $settings : [] );

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

		$override = $settings['override_from'] === '1' || $settings['override_from'] === true;
		if ( $override && ! self::headerExists( $headers, 'From' ) ) {
			$from_email = sanitize_email( (string) $settings['from_email'] );
			if ( is_email( $from_email ) ) {
				$from_name = self::sanitizeFromName( (string) $settings['from_name'] );
				$headers[] = sprintf( 'From: %s <%s>', $from_name, $from_email );
			}
		}

		$reply_email = sanitize_email( (string) ( $settings['reply_to_email'] ?? '' ) );
		if ( is_email( $reply_email ) && ! self::headerExists( $headers, 'Reply-To' ) ) {
			$reply_name = self::sanitizeFromName( (string) ( $settings['reply_to_name'] ?? '' ) );
			$headers[] = sprintf( 'Reply-To: %s <%s>', $reply_name, $reply_email );
		}

		return $headers;
	}

	/**
	 * @param array<int, string> $headers
	 */
	private static function headerExists( array $headers, string $name ): bool {
		$prefix = strtolower( $name ) . ':';
		foreach ( $headers as $header ) {
			if ( stripos( (string) $header, $prefix ) === 0 ) {
				return true;
			}
		}

		return false;
	}

	private static function ensureModuleLoaded(): void {
		if ( class_exists( Module::class ) ) {
			return;
		}
		if ( ! defined( 'WP_POWERSUITE_MODULES_DIR' ) ) {
			return;
		}

		$module_file = WP_POWERSUITE_MODULES_DIR . 'email-smtp' . DIRECTORY_SEPARATOR . 'module.php';
		if ( is_readable( $module_file ) ) {
			require_once $module_file;
		}
	}
}
