<?php
/**
 * Cross-method failure-email registry.
 *
 * Per-method init files register a template-builder callable here. When a
 * payout fails with `failure_class = affiliate_action_required`, the
 * dispatcher (`affwp_maybe_send_failure_email`) pulls the method's
 * template, applies the cross-method cooldown gate, and dispatches via
 * `Affiliate_WP_Emails`.
 *
 * Method slugs that don't register a template silently skip the email
 * step. Store Credit and Manual don't register here because they don't
 * have an affiliate-action-required failure mode in practice.
 *
 * @package    AffiliateWP
 * @subpackage Payouts
 * @since      2.33.0
 */

namespace AffWP\Payouts;

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

/**
 * Method-keyed registry of failure-email templates.
 *
 * @since 2.33.0
 */
final class Failure_Email_Registry {

	/**
	 * Method slug => [ 'label' => string, 'body' => string ].
	 *
	 * The affiliate "payout failed, action required" email is a single email
	 * with a shared subject and a PER-METHOD body. Each payout method that has
	 * an affiliate-action failure mode registers its default body here (and a
	 * human label for the Emails-tab editor). The dispatcher picks the body for
	 * the failed payout's method; the Emails tab renders one editable body per
	 * registered + active method.
	 *
	 * @since 2.33.0
	 * @var array<string, array{label:string,body:string}>
	 */
	private static $methods = array();

	/**
	 * Register a payout method's default failure-email body.
	 *
	 * @since 2.33.0
	 *
	 * @param string $method Method slug (e.g. 'stripe', 'paypal').
	 * @param array  $args {
	 *     @type string $label Human label for the Emails-tab body editor.
	 *     @type string $body  Default body. gettext-translated, method-specific
	 *                         wording, composed from the cross-method tags
	 *                         ({name}, {amount}, {site_name}, {affiliate_payout_settings_url}).
	 * }
	 * @return void
	 */
	public static function register( $method, $args ) {
		if ( ! is_array( $args ) || empty( $args['body'] ) ) {
			return;
		}
		$method = (string) $method;
		self::$methods[ $method ] = array(
			'label' => isset( $args['label'] ) ? (string) $args['label'] : affwp_get_payout_method_display_label( $method ),
			'body'  => (string) $args['body'],
		);
	}

	/**
	 * Whether a method has a failure-email body registered.
	 *
	 * @since 2.33.0
	 *
	 * @param string $method Method slug.
	 * @return bool
	 */
	public static function has_template( $method ) {
		return isset( self::$methods[ (string) $method ] );
	}

	/**
	 * Default body for a method, or '' when none is registered.
	 *
	 * @since 2.33.0
	 *
	 * @param string $method Method slug.
	 * @return string
	 */
	public static function get_body_default( $method ) {
		$method = (string) $method;
		return isset( self::$methods[ $method ] ) ? self::$methods[ $method ]['body'] : '';
	}

	/**
	 * Human label for a method's body editor.
	 *
	 * @since 2.33.0
	 *
	 * @param string $method Method slug.
	 * @return string
	 */
	public static function label( $method ) {
		$method = (string) $method;
		return isset( self::$methods[ $method ] ) ? self::$methods[ $method ]['label'] : (string) $method;
	}

	/**
	 * All registered method slugs.
	 *
	 * @since 2.33.0
	 *
	 * @return string[]
	 */
	public static function methods() {
		return array_keys( self::$methods );
	}
}
