<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * WooCommerce payment methods allowed on Order From DM links.
 * Offline: BACS. Online: real Stripe / PayPal / Mercado Pago gateways (sandbox or live per plugin settings).
 */
class DC_V2_Payment_Methods {

	/** Offline gateways completed inside the chat (no hosted redirect). */
	const OFFLINE_IDS = array( 'bacs' );

	/**
	 * Primary online gateway IDs we surface when enabled in WooCommerce.
	 * (Plugin-specific; brand helpers also match close variants.)
	 */
	const ONLINE_IDS = array(
		'stripe',
		'ppcp-gateway',
		'woo-mercado-pago-basic',
		'woo-mercado-pago-custom',
	);

	/**
	 * @param string $id Gateway id.
	 */
	public static function is_online( $id ) {
		return '' !== self::online_brand( $id );
	}

	/**
	 * @param string $id Gateway id.
	 * @return string stripe|paypal|mercadopago|''
	 */
	public static function online_brand( $id ) {
		$id = strtolower( sanitize_key( (string) $id ) );
		if ( ! $id ) {
			return '';
		}
		if ( 'stripe' === $id || 0 === strpos( $id, 'stripe_' ) ) {
			// Only the main Stripe gateway in the picker — not every UPE method.
			return 'stripe' === $id ? 'stripe' : '';
		}
		if ( false !== strpos( $id, 'paypal' ) || 0 === strpos( $id, 'ppcp' ) ) {
			return 'paypal';
		}
		if ( false !== strpos( $id, 'mercado' ) ) {
			return 'mercadopago';
		}
		return '';
	}

	/**
	 * Whether the gateway is configured enough to attempt checkout (best-effort).
	 *
	 * @param string             $id Gateway id.
	 * @param WC_Payment_Gateway $gw  Gateway instance.
	 */
	public static function gateway_ready( $id, $gw ) {
		$brand = self::online_brand( $id );
		if ( 'stripe' === $brand ) {
			$settings = get_option( 'woocommerce_stripe_settings', array() );
			if ( ! is_array( $settings ) ) {
				return false;
			}
			$test = ( ( $settings['testmode'] ?? '' ) === 'yes' );
			$key  = $test
				? (string) ( $settings['test_publishable_key'] ?? '' )
				: (string) ( $settings['publishable_key'] ?? '' );
			return $key !== '';
		}
		if ( 'paypal' === $brand ) {
			$ppcp = get_option( 'woocommerce-ppcp-settings', array() );
			if ( ! is_array( $ppcp ) ) {
				$ppcp = array();
			}
			$client = (string) ( $ppcp['client_id'] ?? $ppcp['client_id_sandbox'] ?? '' );
			// Connected via onboarding often stores merchant id instead.
			$merchant = (string) ( $ppcp['merchant_id'] ?? $ppcp['merchant_id_sandbox'] ?? '' );
			return $client !== '' || $merchant !== '';
		}
		if ( 'mercadopago' === $brand ) {
			$test_token = (string) get_option( '_mp_access_token_test', '' );
			$prod_token = (string) get_option( '_mp_access_token_prod', '' );
			return $test_token !== '' || $prod_token !== '';
		}
		return is_object( $gw ) && 'yes' === ( $gw->enabled ?? '' );
	}

	/**
	 * True when the plugin is in test/sandbox mode (for UI badge).
	 *
	 * @param string $id Gateway id.
	 */
	public static function is_sandbox_mode( $id ) {
		$brand = self::online_brand( $id );
		if ( 'stripe' === $brand ) {
			$settings = get_option( 'woocommerce_stripe_settings', array() );
			return is_array( $settings ) && ( $settings['testmode'] ?? '' ) === 'yes';
		}
		if ( 'paypal' === $brand ) {
			$env = get_option( 'woocommerce-ppcp-settings', array() );
			if ( is_array( $env ) && isset( $env['sandbox_on'] ) ) {
				return (bool) $env['sandbox_on'] || '1' === (string) $env['sandbox_on'] || 'yes' === (string) $env['sandbox_on'];
			}
			// Fallback: many installs treat missing production credentials as sandbox.
			return true;
		}
		if ( 'mercadopago' === $brand ) {
			// MP stores checkbox_checkout_production_mode as yes/no on gateways; option often "no" = test.
			$prod = get_option( 'checkbox_checkout_production_mode', '' );
			if ( $prod === '' ) {
				$basic = get_option( 'woocommerce_woo-mercado-pago-basic_settings', array() );
				if ( is_array( $basic ) && isset( $basic['checkbox_checkout_test_mode'] ) ) {
					return 'yes' === $basic['checkbox_checkout_test_mode'];
				}
				return true;
			}
			return 'yes' !== $prod;
		}
		return false;
	}

	/**
	 * Store-locale label (Woo method title).
	 *
	 * @param string             $id Gateway id.
	 * @param WC_Payment_Gateway $gw Gateway instance.
	 */
	private static function locale_title( $id, $gw ) {
		$title = '';
		if ( is_object( $gw ) && method_exists( $gw, 'get_method_title' ) ) {
			$title = (string) $gw->get_method_title();
		}
		if ( $title === '' && is_object( $gw ) ) {
			$title = (string) $gw->get_title();
		}
		if ( $title === '' ) {
			switch ( self::online_brand( $id ) ) {
				case 'stripe':
					$title = 'Stripe';
					break;
				case 'paypal':
					$title = 'PayPal';
					break;
				case 'mercadopago':
					$title = 'Mercado Pago';
					break;
				case '':
					$title = 'bacs' === $id ? __( 'Direct bank transfer', 'woocommerce' ) : $id;
					break;
			}
		}
		return $title;
	}

	/**
	 * Short description for admin / chat cards.
	 *
	 * @param string $id Gateway id.
	 */
	private static function method_description( $id ) {
		$brand = self::online_brand( $id );
		if ( 'stripe' === $brand ) {
			return __( 'Card payment via Stripe', 'order-from-dm' );
		}
		if ( 'paypal' === $brand ) {
			return __( 'PayPal checkout', 'order-from-dm' );
		}
		if ( 'mercadopago' === $brand ) {
			return __( 'Mercado Pago checkout', 'order-from-dm' );
		}
		return '';
	}

	/**
	 * @return array<int, array{id:string,title:string,description:string,enabled:bool,ready:bool,needs_setup:bool,accounts?:array,type?:string,brand?:string,sandbox?:bool}>
	 */
	public static function list_available() {
		if ( ! function_exists( 'WC' ) || ! WC()->payment_gateways() ) {
			return array();
		}
		$gateways = WC()->payment_gateways()->payment_gateways();
		$out      = array();

		foreach ( self::OFFLINE_IDS as $id ) {
			if ( empty( $gateways[ $id ] ) ) {
				continue;
			}
			$gw = $gateways[ $id ];
			if ( 'yes' !== $gw->enabled ) {
				continue;
			}
			$ready    = true;
			$needs    = false;
			$accounts = array();
			if ( 'bacs' === $id ) {
				$details  = DC_V2_Order::get_bacs_details();
				$accounts = is_array( $details['accounts'] ?? null ) ? $details['accounts'] : array();
				$ready    = ! empty( $accounts );
				$needs    = ! $ready;
			}
			$out[] = array(
				'id'          => $id,
				'title'       => self::locale_title( $id, $gw ),
				'description' => '',
				'type'        => 'offline',
				'brand'       => $id,
				'enabled'     => true,
				'ready'       => $ready,
				'needs_setup' => $needs,
				'sandbox'     => false,
				'accounts'    => $accounts,
			);
		}

		$seen_brands = array();
		foreach ( self::ONLINE_IDS as $id ) {
			if ( empty( $gateways[ $id ] ) ) {
				continue;
			}
			$gw = $gateways[ $id ];
			if ( 'yes' !== ( $gw->enabled ?? '' ) ) {
				continue;
			}
			$brand = self::online_brand( $id );
			if ( ! $brand ) {
				continue;
			}
			// One card per brand (prefer first ONLINE_IDS match).
			if ( isset( $seen_brands[ $brand ] ) ) {
				continue;
			}
			$seen_brands[ $brand ] = true;
			$ready = self::gateway_ready( $id, $gw );
			$out[] = array(
				'id'          => $id,
				'title'       => self::locale_title( $id, $gw ),
				'description' => self::method_description( $id ),
				'type'        => 'redirect',
				'brand'       => $brand,
				'enabled'     => true,
				'ready'       => $ready,
				'needs_setup' => ! $ready,
				'sandbox'     => self::is_sandbox_mode( $id ),
				'accounts'    => array(),
			);
		}

		return $out;
	}

	/**
	 * @param mixed $raw Selected gateway IDs.
	 * @return string[]
	 */
	public static function normalize( $raw ) {
		$available = array();
		foreach ( self::list_available() as $row ) {
			$available[ $row['id'] ] = true;
		}
		$ids = array();
		if ( is_array( $raw ) ) {
			foreach ( $raw as $id ) {
				$id = sanitize_key( (string) $id );
				// Migrate removed demo gateway ids → real ones when present.
				$id = self::migrate_legacy_id( $id, $available );
				if ( $id && isset( $available[ $id ] ) && ! in_array( $id, $ids, true ) ) {
					$ids[] = $id;
				}
			}
		}
		if ( ! $ids ) {
			if ( isset( $available['bacs'] ) ) {
				return array( 'bacs' );
			}
			$keys = array_keys( $available );
			return $keys ? array( $keys[0] ) : array( 'bacs' );
		}
		return $ids;
	}

	/**
	 * @param string              $id
	 * @param array<string,bool>  $available
	 */
	private static function migrate_legacy_id( $id, $available ) {
		$map = array(
			'ofdm_stripe'      => 'stripe',
			'ofdm_paypal'      => 'ppcp-gateway',
			'ofdm_mercadopago' => 'woo-mercado-pago-basic',
			'cod'              => '',
			'cheque'           => '',
		);
		if ( isset( $map[ $id ] ) ) {
			$mapped = $map[ $id ];
			if ( $mapped && isset( $available[ $mapped ] ) ) {
				return $mapped;
			}
			return '';
		}
		return $id;
	}

	/**
	 * Public payload for chat: selected + still available methods.
	 *
	 * @param string[] $selected
	 * @return array<int, array{id:string,title:string,description:string,type:string,brand:string,sandbox?:bool}>
	 */
	public static function public_methods( $selected ) {
		$selected = self::normalize( $selected );
		$by_id    = array();
		foreach ( self::list_available() as $row ) {
			$by_id[ $row['id'] ] = $row;
		}
		$out = array();
		foreach ( $selected as $id ) {
			if ( empty( $by_id[ $id ] ) ) {
				continue;
			}
			$row = $by_id[ $id ];
			// Hide online methods that are not configured from the customer chat.
			if ( ( $row['type'] ?? '' ) === 'redirect' && ! empty( $row['needs_setup'] ) ) {
				continue;
			}
			$out[] = array(
				'id'          => $row['id'],
				'title'       => $row['title'],
				'description' => $row['description'],
				'type'        => $row['type'] ?? 'offline',
				'brand'       => $row['brand'] ?? $row['id'],
				'sandbox'     => ! empty( $row['sandbox'] ),
			);
		}
		if ( ! $out && ! empty( $by_id['bacs'] ) ) {
			$out[] = array(
				'id'          => 'bacs',
				'title'       => $by_id['bacs']['title'],
				'description' => $by_id['bacs']['description'],
				'type'        => 'offline',
				'brand'       => 'bacs',
				'sandbox'     => false,
			);
		}
		return $out;
	}

	/**
	 * @param string   $method
	 * @param string[] $allowed
	 * @return string|WP_Error
	 */
	public static function validate_choice( $method, $allowed ) {
		$method  = sanitize_key( (string) $method );
		$allowed = self::normalize( $allowed );
		if ( ! $method ) {
			if ( 1 === count( $allowed ) ) {
				return $allowed[0];
			}
			return new WP_Error( 'payment_required', __( 'Select a payment method.', 'order-from-dm' ), array( 'status' => 400 ) );
		}
		$method = self::migrate_legacy_id( $method, array_fill_keys( $allowed, true ) ) ?: $method;
		if ( ! in_array( $method, $allowed, true ) ) {
			return new WP_Error( 'payment_invalid', __( 'That payment method is not available for this link.', 'order-from-dm' ), array( 'status' => 400 ) );
		}
		$ok = false;
		foreach ( self::list_available() as $row ) {
			if ( $row['id'] === $method ) {
				if ( ( $row['type'] ?? '' ) === 'redirect' && ! empty( $row['needs_setup'] ) ) {
					return new WP_Error(
						'payment_setup',
						__( 'That payment method is not configured yet. Add sandbox/live credentials in WooCommerce → Payments.', 'order-from-dm' ),
						array( 'status' => 400 )
					);
				}
				$ok = true;
				break;
			}
		}
		if ( ! $ok ) {
			return new WP_Error( 'payment_unavailable', __( 'That payment method is not available.', 'order-from-dm' ), array( 'status' => 400 ) );
		}
		return $method;
	}

	/**
	 * @param string $id Gateway id.
	 * @return WC_Payment_Gateway|null
	 */
	public static function get_gateway( $id ) {
		if ( ! function_exists( 'WC' ) || ! WC()->payment_gateways() ) {
			return null;
		}
		$gateways = WC()->payment_gateways()->payment_gateways();
		$id       = sanitize_key( $id );
		return ! empty( $gateways[ $id ] ) ? $gateways[ $id ] : null;
	}

	/**
	 * Build chat return URL after hosted payment.
	 *
	 * @param WC_Order $order
	 * @param string   $slug Document slug.
	 */
	public static function chat_return_url( $order, $slug ) {
		$base = DC_V2_Document_CPT::public_url( $slug );
		return add_query_arg(
			array(
				'dc_pay'   => 'return',
				'order_id' => $order->get_id(),
				'key'      => $order->get_order_key(),
			),
			$base
		);
	}

	/**
	 * Start real gateway payment; returns hosted redirect URL.
	 *
	 * @param WC_Order $order
	 * @param string   $payment_method
	 * @param string   $slug
	 * @return array{redirect:string,brand:string}|WP_Error
	 */
	/**
	 * Safely clear Woo notices (REST/chat has no WC session → wc_clear_notices fatals).
	 */
	private static function clear_notices_safe() {
		if ( ! function_exists( 'WC' ) || ! WC() || ! WC()->session ) {
			return;
		}
		if ( function_exists( 'wc_clear_notices' ) ) {
			wc_clear_notices();
		}
	}

	/**
	 * Stripe publishable + secret for current test/live mode.
	 *
	 * @return array{publishable:string,secret:string,sandbox:bool}
	 */
	public static function stripe_keys() {
		$settings = get_option( 'woocommerce_stripe_settings', array() );
		if ( ! is_array( $settings ) ) {
			$settings = array();
		}
		$sandbox = ( $settings['testmode'] ?? '' ) === 'yes';
		return array(
			'publishable' => $sandbox
				? (string) ( $settings['test_publishable_key'] ?? '' )
				: (string) ( $settings['publishable_key'] ?? '' ),
			'secret'      => $sandbox
				? (string) ( $settings['test_secret_key'] ?? '' )
				: (string) ( $settings['secret_key'] ?? '' ),
			'sandbox'     => $sandbox,
		);
	}

	/**
	 * Create a Stripe PaymentIntent for in-chat Payment Element.
	 *
	 * @param WC_Order $order
	 * @param string   $slug
	 * @return array|WP_Error payment_action payload
	 */
	public static function start_stripe_elements_payment( $order, $slug ) {
		$keys = self::stripe_keys();
		if ( $keys['publishable'] === '' || $keys['secret'] === '' ) {
			return new WP_Error(
				'payment_setup',
				__( 'Stripe is not configured. Add test/live keys in WooCommerce → Payments → Stripe.', 'order-from-dm' ),
				array( 'status' => 400 )
			);
		}

		$return_url = self::chat_return_url( $order, $slug );
		$order->update_meta_data( '_dc_v2_chat_return_url', $return_url );
		$order->update_meta_data( '_dc_v2_online_payment', '1' );

		$currency = strtolower( $order->get_currency() );
		$amount   = (float) $order->get_total();
		if ( class_exists( 'WC_Stripe_Helper', false ) && method_exists( 'WC_Stripe_Helper', 'get_stripe_amount' ) ) {
			$stripe_amount = (int) WC_Stripe_Helper::get_stripe_amount( $amount, $currency );
		} else {
			// Zero-decimal currencies are rare in our stores; default to cents.
			$stripe_amount = (int) round( $amount * 100 );
		}

		$intent = null;
		try {
			if ( class_exists( 'WC_Stripe_API', false ) ) {
				WC_Stripe_API::set_secret_key( $keys['secret'] );
				$intent = WC_Stripe_API::request(
					array(
						'amount'               => $stripe_amount,
						'currency'             => $currency,
						'description'          => sprintf( 'Order %s', $order->get_order_number() ),
						'metadata'             => array(
							'order_id' => (string) $order->get_id(),
							'dc_v2'    => '1',
						),
						// Card in chat; keep payload flat-friendly for wp_remote_post.
						'payment_method_types' => array( 'card' ),
					),
					'payment_intents'
				);
			} else {
				$response = wp_remote_post(
					'https://api.stripe.com/v1/payment_intents',
					array(
						'timeout' => 30,
						'headers' => array(
							'Authorization' => 'Bearer ' . $keys['secret'],
						),
						'body'    => array(
							'amount'                   => $stripe_amount,
							'currency'                 => $currency,
							'description'              => sprintf( 'Order %s', $order->get_order_number() ),
							'metadata[order_id]'       => (string) $order->get_id(),
							'metadata[dc_v2]'          => '1',
							'payment_method_types[]'   => 'card',
						),
					)
				);
				if ( is_wp_error( $response ) ) {
					return $response;
				}
				$intent = json_decode( wp_remote_retrieve_body( $response ), true );
			}
		} catch ( Exception $e ) {
			return new WP_Error( 'payment_start_failed', $e->getMessage(), array( 'status' => 400 ) );
		} catch ( Throwable $e ) {
			return new WP_Error( 'payment_start_failed', $e->getMessage(), array( 'status' => 400 ) );
		}
		if ( is_wp_error( $intent ) ) {
			return $intent;
		}

		$client_secret = is_object( $intent )
			? (string) ( $intent->client_secret ?? '' )
			: (string) ( $intent['client_secret'] ?? '' );
		$intent_id     = is_object( $intent )
			? (string) ( $intent->id ?? '' )
			: (string) ( $intent['id'] ?? '' );
		$error_msg     = is_object( $intent )
			? (string) ( $intent->error->message ?? '' )
			: (string) ( $intent['error']['message'] ?? '' );

		if ( $client_secret === '' || $intent_id === '' ) {
			return new WP_Error(
				'payment_start_failed',
				$error_msg !== '' ? $error_msg : __( 'Could not start Stripe payment.', 'order-from-dm' ),
				array( 'status' => 400 )
			);
		}

		$order->update_meta_data( '_dc_v2_stripe_intent_id', $intent_id );
		$order->save();

		return array(
			'type'           => 'stripe_elements',
			'brand'          => 'stripe',
			'publishable_key'=> $keys['publishable'],
			'client_secret'  => $client_secret,
			'intent_id'      => $intent_id,
			'return_url'     => $return_url,
			'order_key'      => $order->get_order_key(),
			'button_label'   => __( 'Pay now', 'order-from-dm' ),
			'hint'           => $keys['sandbox']
				? __( 'Enter your card below — you stay in this chat. Test mode — no real charge.', 'order-from-dm' )
				: __( 'Enter your card below — you stay in this chat.', 'order-from-dm' ),
			'sandbox'        => $keys['sandbox'],
		);
	}

	/**
	 * After Elements confirmPayment, mark the Woo order paid if Stripe says succeeded.
	 *
	 * @param int    $order_id
	 * @param string $key
	 * @return array|WP_Error
	 */
	public static function confirm_stripe_elements_payment( $order_id, $key ) {
		$order = wc_get_order( (int) $order_id );
		if ( ! $order || ! hash_equals( (string) $order->get_order_key(), (string) $key ) ) {
			return new WP_Error( 'not_found', 'Order not found.', array( 'status' => 404 ) );
		}
		if ( ! $order->get_meta( '_dc_v2_document_id' ) ) {
			return new WP_Error( 'not_found', 'Order not found.', array( 'status' => 404 ) );
		}

		if ( $order->is_paid() ) {
			return DC_V2_Order::public_payment_status( $order->get_id(), $key );
		}

		$intent_id = (string) $order->get_meta( '_dc_v2_stripe_intent_id' );
		if ( $intent_id === '' ) {
			return new WP_Error( 'payment_invalid', 'Missing Stripe payment.', array( 'status' => 400 ) );
		}

		$keys = self::stripe_keys();
		$status = '';
		if ( class_exists( 'WC_Stripe_API', false ) ) {
			WC_Stripe_API::set_secret_key( $keys['secret'] );
			$intent = WC_Stripe_API::request( array(), 'payment_intents/' . $intent_id, 'GET' );
			if ( is_wp_error( $intent ) ) {
				return $intent;
			}
			$status = is_object( $intent ) ? (string) ( $intent->status ?? '' ) : (string) ( $intent['status'] ?? '' );
		} else {
			$response = wp_remote_get(
				'https://api.stripe.com/v1/payment_intents/' . rawurlencode( $intent_id ),
				array(
					'timeout' => 30,
					'headers' => array( 'Authorization' => 'Bearer ' . $keys['secret'] ),
				)
			);
			if ( is_wp_error( $response ) ) {
				return $response;
			}
			$body   = json_decode( wp_remote_retrieve_body( $response ), true );
			$status = (string) ( $body['status'] ?? '' );
		}

		if ( 'succeeded' === $status || 'processing' === $status ) {
			$order->payment_complete( $intent_id );
			$order->add_order_note( 'Stripe payment confirmed in Order From DM chat (' . $status . ').' );
			$order->save();
		}

		return DC_V2_Order::public_payment_status( $order->get_id(), $key );
	}

	public static function start_hosted_payment( $order, $payment_method, $slug ) {
		if ( ! $order instanceof WC_Order ) {
			return new WP_Error( 'order_invalid', 'Invalid order.', array( 'status' => 500 ) );
		}
		$gateway = self::get_gateway( $payment_method );
		if ( ! $gateway ) {
			return new WP_Error( 'payment_unavailable', __( 'That payment method is not available.', 'order-from-dm' ), array( 'status' => 400 ) );
		}
		$brand = self::online_brand( $payment_method );

		// Stripe: keep the customer in the chat with Payment Element.
		if ( 'stripe' === $brand ) {
			return self::start_stripe_elements_payment( $order, $slug );
		}

		$return_url = self::chat_return_url( $order, $slug );
		$order->update_meta_data( '_dc_v2_chat_return_url', $return_url );
		$order->update_meta_data( '_dc_v2_online_payment', '1' );
		$order->save();

		$filter = static function ( $url, $o = null ) use ( $return_url, $order ) {
			if ( $o instanceof WC_Order && (int) $o->get_id() === (int) $order->get_id() ) {
				return $return_url;
			}
			if ( ! $o ) {
				return $return_url;
			}
			return $url;
		};
		add_filter( 'woocommerce_get_return_url', $filter, 99, 2 );
		add_filter( 'woocommerce_get_checkout_order_received_url', $filter, 99, 2 );

		$redirect = '';
		try {
			if ( method_exists( $gateway, 'process_payment' ) ) {
				$result = $gateway->process_payment( $order->get_id() );
				if ( is_array( $result ) && ( $result['result'] ?? '' ) === 'success' && ! empty( $result['redirect'] ) ) {
					$redirect = esc_url_raw( (string) $result['redirect'] );
				} else {
					self::clear_notices_safe();
				}
			}
		} catch ( Exception $e ) {
			self::clear_notices_safe();
		} catch ( Throwable $e ) {
			self::clear_notices_safe();
		}

		remove_filter( 'woocommerce_get_return_url', $filter, 99 );
		remove_filter( 'woocommerce_get_checkout_order_received_url', $filter, 99 );

		if ( ! $redirect ) {
			$redirect = $order->get_checkout_payment_url( true );
		}
		if ( ! $redirect ) {
			return new WP_Error(
				'payment_start_failed',
				__( 'Could not start payment. Check the gateway sandbox credentials and try again.', 'order-from-dm' ),
				array( 'status' => 400 )
			);
		}

		$sandbox = self::is_sandbox_mode( $payment_method );
		return array(
			'type'         => 'redirect',
			'brand'        => $brand ?: 'online',
			'redirect_url' => $redirect,
			'button_label' => sprintf(
				/* translators: %s: payment brand name */
				__( 'Pay with %s', 'order-from-dm' ),
				$order->get_payment_method_title() ?: $brand
			),
			'hint'         => $sandbox
				? __( 'You will continue to the secure sandbox checkout, then return here. Test mode — no real charge.', 'order-from-dm' )
				: __( 'You will continue to a secure checkout, then return here.', 'order-from-dm' ),
			'sandbox'      => $sandbox,
		);
	}

	/**
	 * Save a single BACS account into WooCommerce settings.
	 *
	 * @param array  $account account_name, account_number, bank_name.
	 * @param string $instructions Optional BACS instructions.
	 * @return true|WP_Error
	 */
	public static function save_bacs_account( $account, $instructions = '' ) {
		$account_name   = sanitize_text_field( $account['account_name'] ?? '' );
		$account_number = sanitize_text_field( $account['account_number'] ?? '' );
		$bank_name      = sanitize_text_field( $account['bank_name'] ?? '' );
		if ( ! $account_name || ! $account_number ) {
			return new WP_Error( 'bacs_incomplete', __( 'Account holder and account number are required.', 'order-from-dm' ), array( 'status' => 400 ) );
		}
		$accounts = array(
			array(
				'account_name'   => $account_name,
				'account_number' => $account_number,
				'bank_name'      => $bank_name,
				'sort_code'      => '',
				'iban'           => '',
				'bic'            => '',
			),
		);
		update_option( 'woocommerce_bacs_accounts', $accounts );
		$settings = get_option( 'woocommerce_bacs_settings', array() );
		if ( ! is_array( $settings ) ) {
			$settings = array();
		}
		$settings['enabled'] = 'yes';
		if ( is_string( $instructions ) && $instructions !== '' ) {
			$settings['instructions'] = sanitize_textarea_field( $instructions );
		}
		update_option( 'woocommerce_bacs_settings', $settings );
		$gw = self::get_gateway( 'bacs' );
		if ( $gw ) {
			$gw->enabled         = 'yes';
			$gw->account_details = $accounts;
			if ( isset( $settings['instructions'] ) ) {
				$gw->instructions = $settings['instructions'];
			}
		}
		return true;
	}
}
