<?php
/**
 * Template validation helpers.
 *
 * @package MailDoctor
 */

namespace MailDoctor\Email;

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

/**
 * Provides non-blocking validation warnings for templates.
 */
class TemplateValidator {

	/**
	 * Evaluate a template and return non-blocking warnings.
	 *
	 * @param string               $email_type Email identifier.
	 * @param array<string,string> $template   Template fragments.
	 * @return array<int, array<string,string>>
	 */
	public static function validate( string $email_type, array $template ): array {
		$warnings   = array();
		$email_type = sanitize_key( $email_type );
		$html       = isset( $template['html'] ) ? (string) $template['html'] : '';

		if ( self::requires_items_table( $email_type ) && ! self::contains_tag( $html, array( 'order.items_table', 'items_table' ) ) ) {
			$warnings[] = array(
				'code'    => 'missing_items_table',
				'message' => esc_html__( 'Consider including {{ order.items_table }} so customers can review their order items.', 'mail-doctor' ),
			);
		}

		if ( 'customer_reset_password' === $email_type && ! self::contains_tag( $html, array( 'account.reset_url', 'reset_url' ) ) ) {
			$warnings[] = array(
				'code'    => 'missing_reset_link',
				'message' => esc_html__( 'Add {{ account.reset_url }} so customers can reset their password from the email.', 'mail-doctor' ),
			);
		}

		if ( self::requires_branding( $email_type ) && ! self::contains_tag( $html, array( 'store.brand', 'shop_brand' ) ) ) {
			$warnings[] = array(
				'code'    => 'missing_branding',
				'message' => esc_html__( 'Include {{ store.brand }} or {{ shop_brand }} to display your store name or logo.', 'mail-doctor' ),
			);
		}

		/**
		 * Filter template validation warnings before returning to the caller.
		 *
		 * @param array<int, array<string,string>> $warnings   Warning collection.
		 * @param string                           $email_type Email identifier.
		 * @param array<string,string>             $template   Source template fragments.
		 */
		return apply_filters( 'mail_doctor_template_validation_warnings', $warnings, $email_type, $template );
	}

	/**
	 * Determine whether the email should include an items table.
	 */
	protected static function requires_items_table( string $email_type ): bool {
		$order_emails = array(
			'new_order',
			'cancelled_order',
			'customer_on_hold_order',
			'customer_completed_order',
			'customer_processing_order',
			'customer_refunded_order',
			'customer_partially_refunded_order',
			'customer_invoice',
			'customer_note',
		);

		return in_array( $email_type, $order_emails, true );
	}

	/**
	 * Determine whether branding should be encouraged for the email.
	 */
	protected static function requires_branding( string $email_type ): bool {
		return 'customer_reset_password' !== $email_type;
	}

	/**
	 * Check if a template string contains any of the provided merge tags.
	 *
	 * @param string            $html       Template HTML.
	 * @param array<int,string> $candidates Tag identifiers.
	 */
	protected static function contains_tag( string $html, array $candidates ): bool {
		if ( '' === $html ) {
			return false;
		}

		foreach ( $candidates as $candidate ) {
			$candidate = trim( (string) $candidate );

			if ( '' === $candidate ) {
				continue;
			}

			$patterns = array( $candidate );
			$alias    = str_replace( '.', '_', $candidate );
			if ( $alias !== $candidate ) {
				$patterns[] = $alias;
			}

			foreach ( $patterns as $pattern_tag ) {
				$pattern = '/\{\{\s*' . preg_quote( $pattern_tag, '/' ) . '\s*\}\}/i';
				if ( preg_match( $pattern, $html ) ) {
					return true;
				}
			}
		}

		return false;
	}
}
