<?php
namespace Pay4All\Pro\Services;

use Pay4All\Pro\Domain\Newsletter;

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

/**
 * Replaces {token} placeholders in a newsletter body/subject/CTA at send
 * time with per-recipient values. Server-side substitution : the DB stores
 * the raw template once ; the spooler renders one copy per customer.
 *
 * Token catalogue :
 *   {first_name}, {last_name}, {email}, {site_name}, {unsubscribe_url}
 *   {product_title}, {product_price}, {product_url}    (product template)
 *   {promo_code}, {promo_discount}, {promo_expires_at} (promo   template)
 */
final class NewsletterSubstitutor {

	/**
	 * Builds the token map for a given (campaign, customer, lang) triple.
	 * Customer array shape follows \Pay4All\Form\Domain\Customer::list_rows()
	 * (email, firstname, lastname, unsubscribe_token). The optional
	 * $send_track_token is the per-send tracking id issued by
	 * NewsletterSendLog::record() — appended to the unsubscribe URL so
	 * the endpoint can credit the resulting open + unsub against the
	 * correct send_log row (see NewsletterSpooler::rewrite_url_for_tracking).
	 *
	 * @param array<string,mixed> $customer
	 * @return array<string,string>
	 */
	public static function tokens_for( int $campaign_id, array $customer, string $lang, string $send_track_token = '' ) : array {
		$tokens = [
			'first_name'      => (string) ( $customer['firstname'] ?? '' ),
			'last_name'       => (string) ( $customer['lastname']  ?? '' ),
			'email'           => (string) ( $customer['email']     ?? '' ),
			'site_name'       => (string) get_bloginfo( 'name' ),
			'unsubscribe_url' => self::unsubscribe_url( (string) ( $customer['unsubscribe_token'] ?? '' ), $send_track_token ),
		];

		$kind = Newsletter::kind( $campaign_id );
		if ( $kind === Newsletter::KIND_PRODUCT ) {
			$pid = Newsletter::product_id( $campaign_id );
			if ( $pid > 0 && class_exists( '\\Pay4All\\Form\\Domain\\Product' ) ) {
				$tokens['product_title'] = \Pay4All\Form\Domain\Product::display_title( $pid, $lang );
				if ( class_exists( '\\Pay4All\\Form\\Services\\Currency' ) ) {
					$tokens['product_price'] = \Pay4All\Form\Services\Currency::format( \Pay4All\Form\Domain\Product::price( $pid ) );
				} else {
					$tokens['product_price'] = (string) \Pay4All\Form\Domain\Product::price( $pid );
				}
				$tokens['product_url']   = (string) get_permalink( $pid );
			}
		}
		if ( $kind === Newsletter::KIND_PROMO ) {
			$pid = Newsletter::promo_id( $campaign_id );
			if ( $pid > 0 && class_exists( '\\Pay4All\\Form\\Domain\\PromoCode' ) ) {
				$tokens['promo_code']     = \Pay4All\Form\Domain\PromoCode::code( $pid );
				$discount_type   = \Pay4All\Form\Domain\PromoCode::discount_type( $pid );
				$discount_value  = \Pay4All\Form\Domain\PromoCode::discount_value( $pid );
				$tokens['promo_discount'] = self::format_discount( $discount_type, $discount_value );
				$end_iso = \Pay4All\Form\Domain\PromoCode::end_at( $pid );
				$tokens['promo_expires_at'] = $end_iso !== ''
					? wp_date( (string) get_option( 'date_format', 'Y-m-d' ), (int) strtotime( $end_iso ) )
					: '';
			}
		}
		return $tokens;
	}

	/**
	 * Runs the token map through a body / subject / CTA URL / CTA label
	 * string. Missing tokens are left in place — treated as merchant typos
	 * rather than silently blanked so they can spot + fix them in a preview.
	 *
	 * @param array<string,string> $tokens
	 */
	public static function replace( string $subject_or_body, array $tokens ) : string {
		$find    = [];
		$replace = [];
		foreach ( $tokens as $key => $val ) {
			$find[]    = '{' . $key . '}';
			$replace[] = $val;
		}
		return str_replace( $find, $replace, $subject_or_body );
	}

	/**
	 * Builds the public unsubscribe URL. Uses the customer's cryptographic
	 * unsubscribe_token (40 hex, generated at customer creation) — the
	 * endpoint resolves the token back to the customer row and asks for
	 * confirmation before flipping opt_out_promo. When available, the
	 * per-send track_token is appended as `t=…` so the endpoint can log
	 * the open + unsubscribe events against the correct send_log row.
	 */
	public static function unsubscribe_url( string $token, string $send_track_token = '' ) : string {
		if ( $token === '' ) { return home_url( '/' ); }
		$args = [ 'p4all_nl_unsubscribe' => $token ];
		if ( $send_track_token !== '' ) { $args['t'] = $send_track_token; }
		return add_query_arg( $args, home_url( '/' ) );
	}

	private static function format_discount( string $type, float $value ) : string {
		if ( $type === 'percentage' ) {
			$str = rtrim( rtrim( number_format( $value, 2, '.', '' ), '0' ), '.' );
			return $str . ' %';
		}
		if ( $type === 'free_shipping' ) {
			return __( 'free shipping', 'pay4all-pro' );
		}
		if ( $type === 'free_product' ) {
			return __( 'a free product', 'pay4all-pro' );
		}
		if ( class_exists( '\\Pay4All\\Form\\Services\\Currency' ) ) {
			return \Pay4All\Form\Services\Currency::format( $value );
		}
		return (string) $value;
	}
}
