<?php
/**
 * WooCommerce Global Payments HPP
 *
 * This source file is subject to the GNU General Public License v3.0
 * that is bundled with this package in the file license.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.gnu.org/licenses/gpl-3.0.html
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@skyverge.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade WooCommerce Global Payments HPP to newer
 * versions in the future. If you wish to customize WooCommerce Global Payments HPP for your
 * needs please refer to https://docs.woocommerce.com/document/woocommerce-global-payments/ for more information.
 *
 * @author      SkyVerge
 * @copyright   Copyright (c) 2012-2025, SkyVerge, Inc.
 * @license     http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
 */

namespace SkyVerge\WooCommerce\Global_Payments\HPP\APM;

defined( 'ABSPATH' ) or exit;

/**
 * A factory for Alternative_Payment_Method objects
 *
 * @since 2.4.0
 */
class Alternative_Payment_Methods {


	/** @var array a list of payment method properties indexed by ID */
	private static $payment_methods;


	/**
	 * Gets the list of payment method properties index by ID.
	 *
	 * @since 2.4.0
	 *
	 * @return array
	 */
	private static function get_payment_methods() {

		if ( ! is_array( self::$payment_methods ) ) {

			self::$payment_methods =  [
				'testpay'         => [
					'id'         => 'testpay',
					'name'       => 'Testpay',
					'currencies' => [ 'EUR' ],
					'hidden'     => true,
				],
				'alipay'          => [
					'id'         => 'alipay',
					'name'       => 'Alipay',
					'countries'  => [ 'CN' ],
					'currencies' => [ 'AUD', 'CAD', 'EUR', 'GBP', 'HKD', 'NZD', 'SGD', 'USD' ],
				],
				'bancontact'      => [
					'id'         => 'bancontact',
					'name'       => 'Bancontact',
					'countries'  => [ 'BE' ],
					'currencies' => [ 'EUR' ],
				],
				'bitpay'          => [
					'id'         => 'bitpay',
					'name'       => 'Bitpay',
					// worldwide except: Algeria, Bangladesh, Bolivia, Cambodia, Crimea, Cuba, Ecuador, Egypt, Indonesia, Iran, Iraq, Kyrgyzstan, Morocco, Nepal, North Korea, Pakistan, Syria, and Vietnam.
					'countries'  => [],
					'currencies' => [ 'EUR', 'GBP', 'USD' ],
				],
				'EPS'             => [
					'id'         => 'EPS',
					'name'       => 'EPS',
					'countries'  => [ 'AT' ],
					'currencies' => [ 'EUR' ],
				],
				'estonianbanks'   => [
					'id'         => 'estonianbanks',
					'name'       => 'Estonian Banks',
					'countries'  => [ 'EE' ],
					'currencies' => [ 'EUR' ],
				],
				'giropay'         => [
					'id'         => 'giropay',
					'name'       => 'giropay',
					'countries'  => [ 'DE' ],
					'currencies' => [ 'EUR' ],
				],
				'ideal'           => [
					'id'         => 'ideal',
					'name'       => 'Ideal',
					'countries'  => [ 'NL' ],
					'currencies' => [ 'EUR' ],
				],
				'instanttransfer' => [
					'id'         => 'instanttransfer',
					'name'       => 'Instant Transfer',
					'countries'  => [ 'DE' ],
					'currencies' => [ 'EUR' ],
				],
				'latvianbt'       => [
					'id'         => 'latvianbt',
					'name'       => 'Latvian Banks',
					'countries'  => [ 'LV' ],
					'currencies' => [ 'EUR' ],
				],
				'lituanianbt'     => [
					'id'         => 'lituanianbt',
					'name'       => 'Lithuanian Banks',
					'countries'  => [ 'LT' ],
					'currencies' => [ 'EUR' ],
				],
				'maxima'          => [
					'id'         => 'maxima',
					'name'       => 'Maxima',
					'countries'  => [ 'LT' ],
					'currencies' => [ 'EUR' ],
				],
				'multibanco'      => [
					'id'         => 'multibanco',
					'name'       => 'Multibanco',
					'countries'  => [ 'PT' ],
					'currencies' => [ 'EUR' ],
				],
				'mybank'          => [
					'id'         => 'mybank',
					'name'       => 'MyBank',
					'countries'  => [ 'IT', 'ES', 'GR' ],
					'currencies' => [ 'EUR' ],
				],
				'narvesen'        => [
					'id'         => 'narvesen',
					'name'       => 'Narvesen',
					'countries'  => [ 'LT' ],
					'currencies' => [ 'EUR' ],
				],
				'paybybankapp'    => [
					'id'         => 'paybybankapp',
					'name'       => 'PaybyBank app',
					'countries'  => [ 'GB' ],
					'currencies' => [ 'GBP' ],
				],
				'paypost'         => [
					'id'         => 'paypost',
					'name'       => 'PayPost',
					'countries'  => [ 'LT' ],
					'currencies' => [ 'EUR' ],
				],
				'paysera'         => [
					'id'         => 'paysera',
					'name'       => 'Paysera',
					'countries'  => [ 'EE', 'LT', 'LV', 'RU' ],
					'currencies' => [ 'EUR' ],
				],
				'payu'            => [
					'id'         => 'payu',
					'name'       => 'PayU',
					'countries'  => [ 'CZ', 'PL' ],
					'currencies' => [ 'CZK', 'PLN' ],
				],
				'perlas'          => [
					'id'         => 'perlas',
					'name'       => 'Perlas Terminals',
					'countries'  => [ 'LT' ],
					'currencies' => [ 'EUR' ],
				],
				'poli'            => [
					'id'         => 'poli',
					'name'       => 'Poli',
					'countries'  => [ 'AU', 'NZ' ],
					'currencies' => [ 'AUD', 'NZD' ],
				],
				'postfinance'     => [
					'id'         => 'postfinance',
					'name'       => 'Postfinance (YellowPay)',
					'countries'  => [ 'CH' ],
					'currencies' => [ 'CHF', 'EUR' ],
				],
				'p24'             => [
					'id'         => 'p24',
					'name'       => 'Przelewy24 (P24)',
					'countries'  => [ 'PL' ],
					'currencies' => [ 'EUR', 'PLN' ],
				],
				'safetypay'       => [
					'id'         => 'safetypay',
					'name'       => 'Safetypay',
					'countries'  => [ 'AT', 'BE', 'BR', 'CL', 'DE', 'EC', 'ES', 'MX', 'NL', 'PE' ],
					'currencies' => [ 'EUR', 'USD' ],
				],
				'santanderrio'    => [
					'id'         => 'santanderrio',
					'name'       => 'Santander Rio',
					'countries'  => [ 'AR' ],
					'currencies' => [ 'USD' ],
				],
				'santandermx'     => [
					'id'         => 'santandermx',
					'name'       => 'Santander (Mexico)',
					'countries'  => [ 'MX' ],
					'currencies' => [ 'USD' ],
				],
				'santanderbr'     => [
					'id'         => 'santanderbr',
					'name'       => 'Santander (Brazil)',
					'countries'  => [ 'BR' ],
					'currencies' => [ 'USD' ],
				],
				'sepapm'          => [
					'id'         => 'sepapm',
					'name'       => 'SEPA (model A)',
					'countries'  => [ 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'SM' ],
					'currencies' => [ 'EUR' ],
				],
				'sepamm'          => [
					'id'         => 'sepamm',
					'name'       => 'SEPA (model C)',
					'countries'  => [ 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE', 'IS', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SK', 'SM' ],
					'currencies' => [ 'EUR' ],
				],
				'skrill'         => [
					'id'         => 'skrill',
					'name'       => 'Skrill',
					// included in the source spreadsheet as "Intl."
					'countries'  => [],
					'currencies' => [ 'EUR', 'GBP', 'USD' ],
				],
				'sofort'          => [
					'id'         => 'sofort',
					'name'       => 'Sofort',
					'countries'  => [ 'AT', 'BE', 'DE', 'ES', 'IT', 'NL', 'CH*', 'PL*' ],
					'currencies' => [ 'EUR' ],
				],
				'trustpay'       => [
					'id'         => 'trustpay',
					'name'       => 'Trustpay',
					'countries'  => [ 'CZ', 'SK' ],
					'currencies' => [ 'CZK', 'EUR' ],
				],
				'unionpay'        => [
					'id'         => 'unionpay',
					'name'       => 'UnionPay',
					'countries'  => [ 'CN' ],
					'currencies' => [ 'EUR', 'GBP', 'USD' ],
				],
				'osuuspankki'     => [
					'id'         => 'osuuspankki',
					'name'       => 'Osuuspankki',
					'countries'  => [ 'FI' ],
					'currencies' => [ 'EUR' ],
				],
				'poppankki'       => [
					'id'         => 'poppankki',
					'name'       => 'POP Pankki',
					'countries'  => [ 'FI' ],
					'currencies' => [ 'EUR' ],
				],
				'sasstopankki'    => [
					'id'         => 'sasstopankki',
					'name'       => 'Säästöpankki',
					'countries'  => [ 'FI' ],
					'currencies' => [ 'EUR' ],
				],
				'spankki'         => [
					'id'         => 'spankki',
					'name'       => 'S-Pankki',
					'countries'  => [ 'FI' ],
					'currencies' => [ 'EUR' ],
				],
				'wechatpay'       => [
					'id'         => 'wechatpay',
					'name'       => 'Wechat Pay',
					'countries'  => [ 'CN' ],
					'currencies' => [ 'EUR', 'USD', 'GBP' ],
				],
				'zimpler'        => [
					'id'         => 'zimpler',
					'name'       => 'Zimpler',
					'countries'  => [ 'FI', 'SE' ],
					'currencies' => [ 'EUR', 'SEK' ],
				],
			];
		}

		return self::$payment_methods;
	}


	/**
	 * Gets the specified payment method object.
	 *
	 * @since 2.4.0
	 *
	 * @return Alternative_Payment_Method|null
	 */
	public static function get( $payment_method_id ) {

		$payment_methods = self::get_payment_methods();
		$payment_method  = null;

		if ( isset( $payment_methods[ $payment_method_id ] ) ) {
			$payment_method = self::make( $payment_methods[ $payment_method_id ] );
		}

		return $payment_method;
	}


	/**
	 * Creates an Alternative Payment Method instance.
	 *
	 * Returns null if the payment method cannot be created.
	 *
	 * @since 2.4.0
	 *
	 * @param array $args payment method properties
	 * @return Alternative_Payment_Method|null
	 */
	public static function make( $args ) {

		try {
			$payment_method = new Alternative_Payment_Method( $args );
		} catch ( \InvalidArgumentException $e ) {
			$payment_method = null;
		}

		return $payment_method;
	}


	/**
	 * Gets a list of payment method objects that match the given search parameters.
	 *
	 * @since 2.4.0
	 *
	 * @param array $args search parameters
	 * @return Alternative_Payment_Method[]
	 */
	public static function find( $args = [] ) {

		$payment_methods = [];

		$args = self::parse_find_args( $args );

		foreach ( self::get_payment_methods() as $payment_method_id => $payment_method_args ) {

			if ( $args['ids'] && ! in_array( $payment_method_id, $args['ids'], true ) ) {
				continue;
			}

			if ( ! $payment_method = self::make( $payment_method_args ) ) {
				continue;
			}

			if ( $args['currency'] && ! $payment_method->supports_currency( $args['currency'] ) ) {
				continue;
			}

			if ( ! $args['include_hidden'] && $payment_method->is_hidden() ) {
				continue;
			}

			$payment_methods[] = $payment_method;
		}

		return $payment_methods;
	}


	/**
	 * Gets a normalized array of args for Alternative_Payment_Methods::find()
	 *
	 * @since 2.4.0
	 *
	 * @param array $args search parameters
	 * @return array
	 */
	private static function parse_find_args( $args ) {

		$args = wp_parse_args( $args, [
			'ids'            => [],
			'currency'       => null,
			'include_hidden' => false,
		] );

		$args['ids'] = (array) $args['ids'];

		return $args;
	}


}
