<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase, WordPress.Files.FileName.InvalidClassFileName
/**
 * Payment Method Type Registry
 *
 * Centralizes payment method type lookups, gateway ID mappings, and standard
 * gateway type definitions. Replaces the utility functions previously defined
 * in src/payments.php.
 *
 * @package Autoship Cloud
 * @since 2.13.0
 */

namespace Autoship\Modules\Payments\Services;

/**
 * Registry for payment method types, gateway IDs, and gateway type mappings.
 *
 * @package Autoship\Modules\Payments\Services
 * @since 2.13.0
 */
class PaymentMethodTypeRegistry {

	/**
	 * Returns an array of valid payment method IDs mapped to their internal identifiers.
	 *
	 * Replaces autoship_get_valid_payment_methods().
	 *
	 * @return array Payment Method IDs and their identifiers.
	 */
	public function get_valid_methods(): array {
		return apply_filters(
			'autoship_valid_payment_method_ids',
			array(
				'authorize_net_cim_credit_card'       => 'authorize_net',
				'cybersource_credit_card'             => 'cybersource_cc',
				'stripe'                              => 'stripe',
				'stripe_sepa'                         => 'stripe_sepa',
				'stripe_sepa_debit'                   => 'stripe_sepa_debit',
				'trustcommerce'                       => 'trustcommerce',
				'autoship-test-gateway'               => 'test_gateway',
				'ppec_paypal'                         => 'ppec',
				'braintree_credit_card'               => 'braintree',
				'braintree_paypal'                    => 'braintree_paypal',
				'cybersource'                         => 'cybersource',
				'nmi_gateway_woocommerce_credit_card' => 'nmi',
				'sagepaymentsusaapi'                  => 'sagepaymentsusaapi',
				'square_credit_card'                  => 'square',
				'sagepaydirect'                       => 'sage',
				'wc_checkout_com_cards'               => 'checkout_com',
				'nmi'                                 => 'nmi_gateway',
				'airwallex_card'                      => 'airwallex_card',
				'fkwcs_stripe'                        => 'fkwcs_stripe',
				'fkwcs_stripe_ach'                    => 'fkwcs_stripe_ach',
				'woocommerce_payments'                => 'woocommerce_payments',
			)
		);
	}

	/**
	 * Returns the valid payment method QPilot type for a given gateway ID.
	 *
	 * Replaces autoship_get_valid_payment_method_type().
	 *
	 * @param string $method_gateway_id The method gateway ID.
	 *
	 * @return string The valid payment method type, or empty string if not found.
	 */
	public function get_method_type( string $method_gateway_id ): string {
		$types = apply_filters(
			'autoship_valid_payment_method_types',
			array(
				'authorize_net_cim_credit_card'       => 'AuthorizeNet',
				'cybersource_credit_card'             => 'CyberSourceV2',
				'link'                                => 'Stripe',
				'stripe'                              => 'Stripe',
				'stripe_sepa'                         => 'Stripe',
				'stripe_sepa_debit'                   => 'Stripe',
				'trustcommerce'                       => 'TrustCommerce',
				'autoship-test-gateway'               => 'Test',
				'ppec_paypal'                         => 'ppec',
				'braintree_credit_card'               => 'Braintree',
				'braintree_paypal'                    => 'Braintree',
				'cybersource'                         => 'CyberSource',
				'nmi_gateway_woocommerce_credit_card' => 'Nmi',
				'sagepaymentsusaapi'                  => 'PayaV1',
				'square_credit_card'                  => 'Square',
				'sagepaydirect'                       => 'Sage',
				'wc_checkout_com_cards'               => 'Checkout',
				'nmi'                                 => 'Nmi',
				'airwallex_card'                      => 'Airwallex',
				'fkwcs_stripe'                        => 'Stripe',
				'fkwcs_stripe_ach'                    => 'Stripe',
				'woocommerce_payments'                => 'WooPayments',
			)
		);

		return isset( $types[ $method_gateway_id ] ) ? $types[ $method_gateway_id ] : '';
	}

	/**
	 * Returns the standard gateway ID to QPilot type mapping.
	 *
	 * Used for standard (tokenized) gateways. Non-standard (Skyverge) gateways
	 * are added dynamically via the 'autoship_extend_gateway_id_types' filter.
	 *
	 * Replaces autoship_standard_gateway_id_types().
	 *
	 * @return array Gateway IDs mapped to QPilot type names.
	 */
	public function get_standard_gateway_types(): array {
		return apply_filters(
			'autoship_extend_gateway_id_types',
			array(
				'trustcommerce'                       => 'TrustCommerce',
				'cybersource_credit_card'             => 'CyberSource',
				'link'                                => 'Stripe',
				'stripe'                              => 'Stripe',
				'stripe_sepa'                         => 'Stripe',
				'stripe_sepa_debit'                   => 'Stripe',
				'cybersource'                         => 'CyberSource',
				'nmi_gateway_woocommerce_credit_card' => 'Nmi',
				'sagepaymentsusaapi'                  => 'PayaV1',
				'sagepaydirect'                       => 'Sage',
				'wc_checkout_com_cards'               => 'Checkout',
				'nmi'                                 => 'Nmi',
				'airwallex_card'                      => 'Airwallex',
				'fkwcs_stripe'                        => 'Stripe',
				'fkwcs_stripe_ach'                    => 'Stripe',
				'woocommerce_payments'                => 'WooPayments',
			)
		);
	}

	/**
	 * Returns the type of gateway (tokenized or non-standard).
	 *
	 * Replaces autoship_get_payment_method_gateway_type().
	 *
	 * @param string $gateway The gateway ID.
	 *
	 * @return string 'standard' for tokenized gateways, the gateway type for non-standard, or empty string.
	 */
	public function get_gateway_type( string $gateway ): string {
		$types = apply_filters(
			'autoship_payment_method_gateway_type',
			array_merge(
				array(
					'link'                                => 'standard',
					'stripe'                              => 'standard',
					'stripe_sepa'                         => 'standard',
					'stripe_sepa_debit'                   => 'standard',
					'trustcommerce'                       => 'standard',
					'autoship-test-gateway'               => 'test_gateway',
					'ppec_paypal'                         => 'ppec',
					'nmi_gateway_woocommerce_credit_card' => 'standard',
					'sagepaymentsusaapi'                  => 'standard',
					'square_credit_card'                  => 'square',
					'sagepaydirect'                       => 'standard',
					'cybersource'                         => 'standard',
					'wc_checkout_com_cards'               => 'standard',
					'nmi'                                 => 'standard',
					'airwallex_card'                      => 'standard',
					'fkwcs_stripe'                        => 'standard',
					'fkwcs_stripe_ach'                    => 'standard',
					'woocommerce_payments'                => 'standard',
				),
				self::get_late_token_skyverge_gateways()
			)
		);

		return isset( $types[ $gateway ] ) ? $types[ $gateway ] : '';
	}

	/**
	 * Returns the Skyverge gateways that use late tokenization.
	 *
	 * Replaces autoship_get_late_token_skyverge_gateways().
	 *
	 * @return array Gateway IDs mapped to their internal identifiers.
	 */
	public static function get_late_token_skyverge_gateways(): array {
		return array(
			'authorize_net_cim_credit_card' => 'authorize_net',
			'braintree_credit_card'         => 'braintree',
			'braintree_paypal'              => 'braintree_paypal',
			'cybersource_credit_card'       => 'cybersource_cc',
		);
	}

	/**
	 * Resolves a service from the PayPal Payments DI container, returning null on failure.
	 *
	 * PPCP 4.0.3 throws LogicException from PPCP::container() when called before its
	 * Inpsyde Modularity bootstrap completes, and that initial throw leaves the
	 * ReadOnlyContainer in a poisoned state where every subsequent service resolution
	 * (including ->has() and ->get()) also throws. Catching Throwable around both the
	 * container fetch and the service lookup keeps a single early miss from cascading
	 * into request-killing fatals during the "Add Payment Method" flow.
	 *
	 * @param string $service_id The PPCP container service identifier.
	 *
	 * @return mixed The resolved service, or null if the container or service is unavailable.
	 */
	public static function resolve_ppcp_service( string $service_id ) {
		if ( ! class_exists( '\WooCommerce\PayPalCommerce\PPCP' ) ) {
			return null;
		}

		try {
			$container = \WooCommerce\PayPalCommerce\PPCP::container();
			if ( ! $container->has( $service_id ) ) {
				return null;
			}

			return $container->get( $service_id );
		} catch ( \Throwable $e ) {
			return null;
		}
	}

	/**
	 * Returns whether PPCP has PayPal vaulting enabled for the main PayPal gateway.
	 *
	 * PPCP 4.x replaced the legacy `vault_enabled` checkbox with a `subscriptions_mode`
	 * dropdown whose `vaulting_api` value indicates the same capability. Merchants
	 * configured through the newer UI have `vault_enabled = false` despite having
	 * vaulting fully turned on, so both signals must be honored.
	 *
	 * @param object $ppcp_settings The PPCP settings service (already resolved).
	 *
	 * @return bool
	 */
	private static function is_ppcp_paypal_vault_enabled( $ppcp_settings ): bool {
		if ( $ppcp_settings->has( 'vault_enabled' ) && $ppcp_settings->get( 'vault_enabled' ) ) {
			return true;
		}

		if ( $ppcp_settings->has( 'subscriptions_mode' ) && 'vaulting_api' === $ppcp_settings->get( 'subscriptions_mode' ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Filters the payment method gateway types for optional gateways (PPCP).
	 *
	 * Replaces autoship_adjust_payment_method_gateway_type_for_optional_gateways().
	 *
	 * @param array $types The types to filter.
	 *
	 * @return array The filtered types.
	 */
	public static function adjust_gateway_type_for_optional_gateways( array $types ): array {
		$ppcp_settings = self::resolve_ppcp_service( 'wcgateway.settings' );
		if ( null === $ppcp_settings ) {
			return $types;
		}

		if ( self::is_ppcp_paypal_vault_enabled( $ppcp_settings ) ) {
			$types['ppcp-gateway'] = 'ppcp';
		}

		if ( $ppcp_settings->has( 'vault_enabled_dcc' ) && $ppcp_settings->get( 'vault_enabled_dcc' ) ) {
			$types['ppcp-credit-card-gateway'] = 'ppcp_cc';
		}

		return $types;
	}

	/**
	 * Filters the valid payment method IDs for optional gateways (PPCP, COD).
	 *
	 * Replaces autoship_enable_payment_method_ids_for_optional_gateways().
	 *
	 * @param array $types The types to filter.
	 *
	 * @return array The filtered types.
	 */
	public static function enable_payment_method_ids_for_optional_gateways( array $types ): array {
		$ppcp_settings = self::resolve_ppcp_service( 'wcgateway.settings' );

		if ( null !== $ppcp_settings ) {
			if ( self::is_ppcp_paypal_vault_enabled( $ppcp_settings ) ) {
				$types['ppcp-gateway'] = 'ppcp';
			}

			if ( $ppcp_settings->has( 'vault_enabled_dcc' ) && $ppcp_settings->get( 'vault_enabled_dcc' ) ) {
				$types['ppcp-credit-card-gateway'] = 'ppcp_cc';
			}
		}

		if ( 'yes' === autoship_get_support_cod_payments_option() ) {
			$types['cod'] = 'payment_method_cod';
		}

		return $types;
	}

	/**
	 * Filters the valid payment method types for optional gateways (PPCP V3).
	 *
	 * Replaces autoship_enable_payment_method_types_for_optional_gateways().
	 *
	 * @param array $types The types to filter.
	 *
	 * @return array The filtered types.
	 */
	public static function enable_payment_method_types_for_optional_gateways( array $types ): array {
		// resolve_ppcp_service() handles both the missing-service case (vaulting not
		// registered when the merchant hasn't enabled vaulting on PayPal) and the
		// poisoned-container case where the service lookup itself throws.
		if ( ! self::resolve_ppcp_service( 'vaulting.vault-v3-enabled' ) ) {
			return $types;
		}

		$types['ppcp-gateway']             = 'PayPalV3';
		$types['ppcp-credit-card-gateway'] = 'PayPalV3';

		return $types;
	}

	/**
	 * Adds support for the Skyverge Framework Token Version gateways.
	 *
	 * Replaces autoship_add_skyverge_token_support().
	 *
	 * @param array $types The current types array.
	 *
	 * @return array The filtered types.
	 */
	public static function add_skyverge_token_support( array $types ): array {
		if ( class_exists( 'WC_Braintree' ) && version_compare( \WC_Braintree::VERSION, '2.5.0', '>=' ) ) {
			$types['braintree_credit_card'] = 'Braintree';
			$types['braintree_paypal']      = 'Braintree';
		}

		if ( class_exists( 'WC_Authorize_Net_CIM' ) && version_compare( \WC_Authorize_Net_CIM::VERSION, '3.3.0', '>=' ) ) {
			$types['authorize_net_cim_credit_card'] = 'AuthorizeNet';
		}

		return $types;
	}

	/**
	 * Adds support for the PayPal Payments (PayPal V3) token types.
	 *
	 * Replaces autoship_add_paypal_v3_token_support().
	 *
	 * @param array $types The current types array.
	 *
	 * @return array The filtered types.
	 */
	public static function add_paypal_v3_token_support( array $types ): array {
		$ppcp_settings = self::resolve_ppcp_service( 'wcgateway.settings' );
		if ( null === $ppcp_settings ) {
			return $types;
		}

		if ( self::is_ppcp_paypal_vault_enabled( $ppcp_settings ) ) {
			$types['ppcp-gateway'] = 'PayPalV3';
		}

		if ( $ppcp_settings->has( 'vault_enabled_dcc' ) && $ppcp_settings->get( 'vault_enabled_dcc' ) ) {
			$types['ppcp-credit-card-gateway'] = 'PayPalV3';
		}

		return $types;
	}

	/**
	 * Adds the standard types for the Skyverge Framework Token Version gateways.
	 *
	 * Replaces autoship_add_skyverge_stanard_types().
	 *
	 * @param array $types The current types array.
	 *
	 * @return array The filtered types.
	 */
	public static function add_skyverge_standard_types( array $types ): array {
		if ( class_exists( 'WC_Braintree' ) && version_compare( \WC_Braintree::VERSION, '2.5.0', '>=' ) ) {
			$types['braintree_credit_card'] = 'standard';
			$types['braintree_paypal']      = 'standard';
		}

		if ( class_exists( 'WC_Authorize_Net_CIM' ) && version_compare( \WC_Authorize_Net_CIM::VERSION, '3.3.0', '>=' ) ) {
			$types['authorize_net_cim_credit_card'] = 'standard';
		}

		if ( class_exists( 'WC_Cybersource_Loader' ) && version_compare( \WC_Cybersource_Loader::FRAMEWORK_VERSION, '5.8.0', '>=' ) ) {
			$types['cybersource_credit_card'] = 'standard';
		}

		return $types;
	}

	/**
	 * Register filter callbacks for optional gateway support.
	 *
	 * This should be called during module boot to register the filter callbacks
	 * that extend the base type arrays for optional gateways.
	 *
	 * @return void
	 */
	public static function register_filters(): void {
		add_filter( 'autoship_payment_method_gateway_type', array( self::class, 'adjust_gateway_type_for_optional_gateways' ), 10, 1 );
		add_filter( 'autoship_valid_payment_method_ids', array( self::class, 'enable_payment_method_ids_for_optional_gateways' ), 10, 1 );
		add_filter( 'autoship_valid_payment_method_types', array( self::class, 'enable_payment_method_types_for_optional_gateways' ), 10, 1 );
		add_filter( 'autoship_extend_gateway_id_types', array( self::class, 'add_skyverge_token_support' ), 11, 1 );
		add_filter( 'autoship_extend_gateway_id_types', array( self::class, 'add_paypal_v3_token_support' ), 12, 1 );
		add_filter( 'autoship_payment_method_gateway_type', array( self::class, 'add_skyverge_standard_types' ), 10, 1 );
	}
}
