<?php

namespace PaymentPage\Email;

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

use PaymentPage\Model\Payments as PP_Model_Payments;

/**
 * Confirmation email merge tags + body building (Shortcut #6932 / prompt 04c).
 */
class ConfirmationEmail {

	/**
	 * Locked 11-tag set (CEO decision 2026-05-16).
	 *
	 * @return list<string>
	 */
	public static function merge_tag_list(): array {
		return array(
			'{customer_name}',
			'{customer_email}',
			'{form_name}',
			'{amount}',
			'{currency}',
			'{payment_date}',
			'{order_id}',
			'{site_name}',
			'{first_name}',
			'{last_name}',
			'{frequency}',
		);
	}

	/**
	 * @param array<string, mixed> $request_data From Webhook::_onPaymentSuccess.
	 */
	public static function build_merge_context( PP_Model_Payments $model_payment, array $request_data ): array {
		$amount_int = isset( $request_data['amount_received'] ) ? intval( $request_data['amount_received'] ) : intval( $model_payment->amount_received );
		$currency    = isset( $request_data['currency'] ) ? (string) $request_data['currency'] : (string) $model_payment->currency;

		$frequency = '';
		if ( isset( $model_payment->metadata_json['frequency'] ) ) {
			$frequency = (string) $model_payment->metadata_json['frequency'];
		} elseif ( isset( $request_data['frequency'] ) ) {
			$frequency = (string) $request_data['frequency'];
		}

		$payment_ts = isset( $model_payment->updated_at ) ? intval( $model_payment->updated_at ) : time();
		if ( $payment_ts <= 0 ) {
			$payment_ts = time();
		}

		return array(
			'{customer_name}'   => trim( $model_payment->first_name . ' ' . $model_payment->last_name ),
			'{customer_email}'  => (string) $model_payment->email_address,
			'{form_name}'       => get_the_title( intval( $model_payment->post_id ) ),
			'{amount}'          => payment_page_format_decimal_int_price_as_readable( $amount_int, $currency ),
			'{currency}'        => strtoupper( $currency ),
			'{payment_date}'    => wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $payment_ts ),
			'{order_id}'        => (string) intval( $model_payment->id ),
			'{site_name}'       => get_bloginfo( 'name' ),
			'{first_name}'      => (string) $model_payment->first_name,
			'{last_name}'       => (string) $model_payment->last_name,
			'{frequency}'       => $frequency,
		);
	}

	public static function apply_merge_tags( string $template, array $merge_context ): string {
		return strtr( $template, $merge_context );
	}

	/**
	 * Plain-text companion for HTML bodies (AltBody / assertions).
	 */
	public static function html_to_plaintext( string $html ): string {
		return wp_strip_all_tags( str_replace( array( '<br />', '<br>', '<br/>' ), "\n", $html ) );
	}

	/**
	 * Legacy auto-generated HTML body (unordered list of request_data).
	 *
	 * @param array<string, mixed> $request_data
	 */
	public static function build_legacy_html_body( array $request_data ): string {
		$content  = '';
		$content .= '<ul style="list-style-type:none;padding:0;margin:0;">';

		foreach ( $request_data as $k => $v ) {
			if ( $k === 'gateway' ) {
				$value = ucfirst( (string) $v );
			} elseif ( $k === 'currency' ) {
				$value = strtoupper( (string) $v );
			} elseif ( $k === 'method' ) {
				if ( $v === 'ccard' ) {
					$value = __( 'Credit Card', 'payment-page' );
				} else {
					$value = ucwords( (string) $v );
				}
			} elseif ( is_array( $v ) ) {
				$value = wp_json_encode( $v, JSON_PRETTY_PRINT );
			} elseif ( is_numeric( $v ) ) {
				if ( stripos( (string) $k, 'amount' ) !== false ) {
					$value = payment_page_format_decimal_int_price_as_readable( intval( $v ), isset( $request_data['currency'] ) ? (string) $request_data['currency'] : 'usd' );
				} else {
					$value = $v;
				}
			} elseif ( stripos( (string) $k, 'domain' ) === false && stripos( (string) $k, 'url' ) === false ) {
				$value = ucfirst( (string) $v );
			} else {
				$value = (string) $v;
			}

			$content .= '<li><strong>' . payment_page_alias_to_label( (string) $k ) . '</strong>: ' . esc_html( is_scalar( $value ) ? (string) $value : wp_json_encode( $value ) ) . '</li>';
		}

		$content .= '</ul>';

		return $content;
	}

	/**
	 * @param array<string, mixed> $page_settings
	 * @param array<string, mixed> $request_data
	 */
	public static function build_body( string $which, array $page_settings, PP_Model_Payments $model_payment, array $request_data ): string {
		$key = ( $which === 'payer' ) ? 'email_body_payer' : 'email_body_admin';

		$merge = self::build_merge_context( $model_payment, $request_data );

		if ( isset( $page_settings[ $key ] ) && is_string( $page_settings[ $key ] ) && trim( $page_settings[ $key ] ) !== '' ) {
			$raw = self::apply_merge_tags( $page_settings[ $key ], $merge );

			return nl2br( esc_html( $raw ), false );
		}

		return self::build_legacy_html_body( $request_data );
	}

	/**
	 * Build the "From: Name <email>" header for outbound payment-form emails.
	 *
	 * Returns '' when no header should be added (caller falls back to WP defaults).
	 *
	 * Strategy A read-time fallback: when email_from is empty but email_from_name
	 * is set and email_to is a single valid address, promote email_to into the
	 * From: header only — never touch the recipient. This recovers the merchant's
	 * intent on forms saved by the 1.4.9 dup-key bug (where the "From email"
	 * input incorrectly wrote to the email_to meta key) without the destructive
	 * 1.4.10 migration that silently re-targeted Case-B users' admin notifications.
	 *
	 * @param array<string, mixed> $page_settings
	 */
	public static function build_from_header( array $page_settings ): string {
		$from_name_raw = isset( $page_settings['email_from_name'] ) ? (string) $page_settings['email_from_name'] : '';
		$from_name     = sanitize_text_field( $from_name_raw );

		if ( $from_name === '' ) {
			return '';
		}

		$from_email = isset( $page_settings['email_from'] ) ? trim( (string) $page_settings['email_from'] ) : '';

		if ( $from_email === '' ) {
			$to_raw = isset( $page_settings['email_to'] ) ? (string) $page_settings['email_to'] : '';
			if ( $to_raw === '' || strpos( $to_raw, ',' ) !== false ) {
				return '';
			}
			$candidate = trim( $to_raw );
			if ( ! is_email( $candidate ) ) {
				return '';
			}
			$from_email = $candidate;
		} else {
			if ( ! is_email( $from_email ) ) {
				return '';
			}
		}

		return 'From: ' . $from_name . ' <' . $from_email . '>';
	}

	/**
	 * Wrap wp_mail to attach a plain-text AltBody derived from HTML.
	 *
	 * @param callable():bool|mixed $send Returns wp_mail result.
	 * @return mixed
	 */
	public static function with_plaintext_alt( string $html_body, $send ) {
		$cb = function( $phpmailer ) use ( $html_body ) {
			if ( ! is_object( $phpmailer ) || ! isset( $phpmailer->ContentType ) ) {
				return;
			}
			if ( stripos( (string) $phpmailer->ContentType, 'text/html' ) === false ) {
				return;
			}
			$text                    = wp_strip_all_tags( str_replace( array( '<br />', '<br>', '<br/>' ), "\n", $html_body ) );
			$phpmailer->AltBody = $text;
		};

		add_action( 'phpmailer_init', $cb, 10, 1 );
		try {
			return $send();
		} finally {
			remove_action( 'phpmailer_init', $cb, 10 );
		}
	}
}
