<?php
/**
 * Helpers for parsing and validating wp_mail headers.
 *
 * @package WP_PowerSuite\Email
 */

namespace WP_PowerSuite\Email;

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

final class MailHeaders {

	/**
	 * @param string|array<int, string> $headers
	 * @return list<string>
	 */
	public static function normalizeLines( $headers ): array {
		if ( is_string( $headers ) ) {
			$headers = preg_split( '/\r\n|\r|\n/', $headers ) ?: [];
		}

		if ( ! is_array( $headers ) ) {
			return [];
		}

		$lines = [];
		foreach ( $headers as $header ) {
			$header = trim( (string) $header );
			if ( $header !== '' ) {
				$lines[] = $header;
			}
		}

		return $lines;
	}

	/**
	 * Store headers without strip_tags(), which removes addresses in angle brackets.
	 */
	public static function sanitizeForStorage( string $headers ): string {
		$headers = str_replace( [ "\0", "\r" ], '', $headers );
		$headers = preg_replace( "/\n{3,}/", "\n\n", $headers ) ?? $headers;

		return trim( $headers );
	}

	/**
	 * Parse wp_mail-style recipients into validated email addresses.
	 *
	 * @param mixed $addresses
	 * @return list<string>
	 */
	public static function parseAddresses( $addresses ): array {
		$emails = [];

		if ( is_array( $addresses ) ) {
			foreach ( $addresses as $key => $entry ) {
				if ( is_array( $entry ) ) {
					$entry = $entry[0] ?? '';
				}

				if ( is_string( $key ) && is_email( $key ) ) {
					$emails[] = sanitize_email( $key );
					continue;
				}

				if ( is_string( $entry ) && is_email( $entry ) ) {
					$emails[] = sanitize_email( $entry );
					continue;
				}

				if ( is_string( $entry ) && $entry !== '' ) {
					$emails = array_merge( $emails, self::parseAddresses( $entry ) );
				}
			}

			return array_values( array_unique( array_filter( $emails ) ) );
		}

		$parts = preg_split( '/[,;]\s*/', (string) $addresses ) ?: [];
		foreach ( $parts as $part ) {
			$part = trim( (string) $part );
			if ( $part === '' ) {
				continue;
			}

			$email = self::extractAddress( $part );
			if ( $email !== '' ) {
				$emails[] = $email;
			}
		}

		return array_values( array_unique( $emails ) );
	}

	public static function extractAddress( string $address ): string {
		$address = trim( $address );
		if ( $address === '' ) {
			return '';
		}

		if ( preg_match( '/(.*)<(.+)>/', $address, $matches ) && count( $matches ) === 3 ) {
			$address = trim( $matches[2] );
		}

		$address = trim( $address, " \t\n\r\0\x0B\"'" );
		$address = sanitize_email( $address );

		return is_email( $address ) ? $address : '';
	}

	/**
	 * @param list<string> $headers
	 * @return list<string>
	 */
	public static function dropInvalidAddressHeaders( array $headers ): array {
		$clean = [];

		foreach ( $headers as $header ) {
			if ( self::isValidHeaderLine( (string) $header ) ) {
				$clean[] = $header;
			}
		}

		return $clean;
	}

	public static function isValidHeaderLine( string $header ): bool {
		$header = trim( $header );
		if ( $header === '' || ! str_contains( $header, ':' ) ) {
			return false;
		}

		[ $name, $value ] = array_pad( explode( ':', $header, 2 ), 2, '' );
		$name              = strtolower( trim( $name ) );

		if ( ! in_array( $name, [ 'from', 'reply-to', 'cc', 'bcc' ], true ) ) {
			return true;
		}

		return self::parseAddresses( trim( $value ) ) !== [];
	}

	/**
	 * Apply configured sender headers and drop malformed address headers first.
	 *
	 * @param array<int, string> $headers
	 * @return list<string>
	 */
	public static function applyIdentityHeaders( array $headers ): array {
		$headers = self::dropInvalidAddressHeaders( $headers );

		if ( class_exists( '\EmailSmtp\Includes\SmtpSettingsHelper' ) ) {
			return \EmailSmtp\Includes\SmtpSettingsHelper::prepareOutgoingMailHeaders( $headers );
		}

		if ( class_exists( '\CustomWpEmails\Includes\SystemEmailService' ) ) {
			return \CustomWpEmails\Includes\SystemEmailService::build_mail_headers( $headers );
		}

		return $headers;
	}
}
