<?php

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

if ( ! class_exists( 'WC_Connect_PayPal_EC' ) ) {

	/**
	 * Integrates with WooCommerce PayPal Checkout Payment Gateway,
	 * modifying that plugin's behavior to facilitate authenticating requests
	 * not by linking an account but via the WCS server through which we proxy.
	 */
	class WC_Connect_PayPal_EC {

		/**
		 * @var WC_Connect_API_Client
		 */
		private $api_client;

		/**
		 * @var WC_Connect_Nux
		 */
		private $nux;

		/**
		 * Express Checkout API methods to proxy.
		 */
		private $methods_to_proxy = array( 'SetExpressCheckout', 'GetExpressCheckoutDetails', 'DoExpressCheckoutPayment' );

		public function __construct( WC_Connect_API_Client $api_client, WC_Connect_Nux $nux ) {
			$this->api_client = $api_client;
			$this->nux        = $nux;
		}

		public function init() {
			if ( ! function_exists( 'wc_gateway_ppec' ) ) {
				return;
			}

			$ppec_plugin = wc_gateway_ppec();
			if ( ! property_exists( $ppec_plugin, 'settings' ) || empty( $ppec_plugin->settings ) ) {
				return;
			}

			$this->maybe_set_reroute_requests();

			add_filter( 'woocommerce_paypal_express_checkout_settings', array( $this, 'adjust_form_fields' ) );
			$this->initialize_settings();
			$settings = $ppec_plugin->settings;

			// Don't modify any PPEC plugin behavior if WCS request proxying is not enabled
			if ( 'yes' !== $settings->reroute_requests ) {
				return;
			}

			// If empty, populate Sandbox and Live API Subject values with provided email
			if (
				empty( $settings->sandbox_api_subject ) &&
				empty( $settings->sandbox_api_username ) &&
				empty( $settings->api_username )
			) {
				$email                         = isset( $settings->email ) ? $settings->email : $settings->api_subject;
				$settings->api_subject         = $email;
				$settings->sandbox_api_subject = $email;
				$settings->save();
			}

			$username = $settings->get_active_api_credentials()->get_username();
			$subject  = $settings->get_active_api_credentials()->get_subject();

			// Proceed to attach PPEC-related hooks if email address is present but credentials are missing
			if ( empty( $username ) && ! empty( $subject ) ) {
				add_filter( 'woocommerce_paypal_express_checkout_request_body', array( $this, 'request_body' ) );

				add_filter( 'option_woocommerce_ppec_paypal_settings', array( $this, 'adjust_settings' ) );
				add_filter( 'woocommerce_payment_gateway_supports', array( $this, 'ppec_supports' ), 10, 3 );

				if ( 'live' === $settings->environment ) {
					// If PPEC order comes in, activate prompt to connect a PayPal account
					add_action( 'woocommerce_order_status_on-hold', array( $this, 'maybe_trigger_banner' ) );
					add_action( 'woocommerce_payment_complete', array( $this, 'maybe_trigger_banner' ) );

					// Once a payment is received, show prompt to connect a PayPal account on certain screens
					add_action( 'admin_enqueue_scripts', array( $this, 'maybe_show_banner' ) );

					add_filter( 'wc_services_pointer_post.php', array( $this, 'register_refund_pointer' ) );
				}
				add_filter( 'pre_option_wc_gateway_ppce_prompt_to_connect', '__return_empty_string' ); // Disable default PPEC notice.
			}
		}

		/**
		 * Attach request proxying hook if it's an Express Checkout method
		 */
		public function request_body( $body ) {
			if ( in_array( $body['METHOD'], $this->methods_to_proxy ) ) {
				add_filter( 'pre_http_request', array( $this, 'proxy_request' ), 10, 3 );
			} else {
				remove_filter( 'pre_http_request', array( $this, 'proxy_request' ), 10, 3 );
			}
			return $body;
		}

		/**
		 * Reroute Express Checkout requests from the PPEC extension via WCS server to pick up API credentials
		 */
		public function proxy_request( $preempt, $r, $url ) {
			if ( ! preg_match( '/paypal.com\/nvp$/', $url ) ) {
				return $preempt;
			}

			$settings = wc_gateway_ppec()->settings;
			return $this->api_client->proxy_request( 'paypal/nvp/' . $settings->environment, $r );
		}

		/**
		 * Limit supported payment gateway features to payments alone
		 */
		public function ppec_supports( $supported, $feature, $gateway ) {
			return 'ppec_paypal' === $gateway->id ? 'products' === $feature : $supported;
		}

		/**
		 * Add a pointer clarifying the need to link an account before refunding payment
		 */
		public function register_refund_pointer( $pointers ) {
			$pointers[] = array(
				'id'              => 'wc_services_refund_via_ppec',
				'target'          => '.refund-actions > button:first-child',
				'options'         => array(
					'content'  => sprintf(
						'<h3>%s</h3><p>%s</p>',
						__( 'Link a PayPal account', 'woocommerce-services' ),
						sprintf(
							wp_kses(
								__( 'To issue refunds via PayPal Checkout, you will need to <a href="%s">link a PayPal account</a> with the email address that received this payment.', 'woocommerce-services' ),
								array( 'a' => array( 'href' => array() ) )
							),
							wc_gateway_ppec()->ips->get_signup_url( wc_gateway_ppec()->settings->environment )
						)
					),
					'position' => array(
						'edge'  => 'bottom',
						'align' => 'top',
					),
				),
				'delayed_opening' => array(
					'show_button'          => '.refund-items',
					'hide_button'          => '.cancel-action',
					'animating_container'  => '.wc-order-refund-items',
					'delegation_container' => '#woocommerce-order-items',
				),
			);

			return $pointers;
		}

		/**
		 * Trigger banner to appear based on order paid with PPEC
		 */
		public function maybe_trigger_banner( $order_id ) {
			$order          = wc_get_order( $order_id );
			$payment_method = $order ? $order->get_payment_method() : false;

			if ( 'ppec_paypal' === $payment_method ) {
				WC_Connect_Options::update_option( 'banner_ppec', 'yes' );
			}
		}

		/**
		 * Show banner if it has been triggered and if this screen is an appropriate place for it
		 */
		public function maybe_show_banner() {
			if ( 'yes' !== WC_Connect_Options::get_option( 'banner_ppec', null ) ) {
				return;
			}

			$screen = get_current_screen();

			$order          = wc_get_order();
			$payment_method = $order ? $order->get_payment_method() : false;

			if ( // Display if on any of these admin pages.
				( // Orders list.
					'shop_order' === $screen->post_type
					&& 'edit' === $screen->base
					)
				|| ( // Edit order page.
					'shop_order' === $screen->post_type
					&& 'post' === $screen->base
					&& 'ppec_paypal' === $payment_method
					)
				|| ( // WooCommerce » Settings » Payments.
					'woocommerce_page_wc-settings' === $screen->base
					&& isset( $_GET['tab'] ) && 'checkout' === $_GET['tab']
					)
				|| ( // WooCommerce » Extensions » Payments.
					'woocommerce_page_wc-addons' === $screen->base
					&& isset( $_GET['section'] ) && 'payment-gateways' === $_GET['section']
					)
			) {
				wp_enqueue_style( 'wc_connect_banner' );
				add_action( 'admin_notices', array( $this, 'banner' ) );
			}
		}

		/**
		 * Show a NUX banner prompting the merchant to link a PayPal account
		 */
		public function banner() {
			$this->nux->show_nux_banner(
				array(
					'title'          => __( 'Link your PayPal account', 'woocommerce-services' ),
					'description'    => esc_html( __( 'Link a new or existing PayPal account to make sure future orders are marked “Processing” instead of “On hold”, and so refunds can be issued without leaving WooCommerce.', 'woocommerce-services' ) ),
					'button_text'    => __( 'Link account', 'woocommerce-services' ),
					'button_link'    => wc_gateway_ppec()->ips->get_signup_url( 'live' ),
					'image_url'      => plugins_url( 'images/cashier.svg', __DIR__ ),
					'should_show_jp' => false,
					'dismissible_id' => 'ppec',
				)
			);
		}

		/**
		 * Initialize PPEC settings to their default values
		 */
		public function initialize_settings() {
			$settings = get_option( 'woocommerce_ppec_paypal_settings', array() );

			if ( ! isset( $settings['reroute_requests'] ) ) {
				$settings['reroute_requests'] = 'no';
			} elseif ( 'no' === $settings['reroute_requests'] ) {
				return;
			} elseif ( ! isset( $settings['button_size'] ) ) { // Check if settings are initialized, represented by button_size as its absence would be first to affect the customer
				$payment_gateways = WC()->payment_gateways->payment_gateways();
				$gateway          = $payment_gateways['ppec_paypal'];

				foreach ( $gateway->form_fields as $key => $form_field ) {
					if ( ! isset( $settings[ $key ] ) && isset( $form_field['default'] ) ) {
						$settings[ $key ] = $form_field['default'];
					}
				}
			}

			update_option( 'woocommerce_ppec_paypal_settings', $settings );
			wc_gateway_ppec()->settings->load( true );
		}

		/**
		 * Force setting values that will work when proxying requests
		 */
		public function adjust_settings( $settings ) {
			$settings['paymentaction'] = 'sale';
			return $settings;
		}

		/**
		 * Modify PPEC settings form to include a toggle (and other accommodations) for WCS request proxying
		 */
		public function adjust_form_fields( $form_fields ) {
			$settings = wc_gateway_ppec()->settings;

			// Modify form fields and descriptions depending on whether WCS request proxying is enabled
			if ( 'yes' === $settings->reroute_requests ) {
				$form_fields = $this->adjust_api_subject_form_field( $form_fields );

				// Prevent user from changing Payment Action away from "Sale", the only option for which payments will work
				$form_fields['paymentaction']['disabled']    = true;
				$form_fields['paymentaction']['description'] = sprintf( __( '%s (Note that "authorizing payment only" requires linking a PayPal account.)', 'woocommerce-services' ), $form_fields['paymentaction']['description'] );

				// Communicate WCS proxying and provide option to disable
				$reset_link         = add_query_arg(
					array(
						'reroute_requests' => 'no',
						'nonce'            => wp_create_nonce( 'reroute_requests' ),
					),
					wc_gateway_ppec()->get_admin_setting_link()
				);
				$api_creds_template = __( 'Payments will be authenticated by WooCommerce Tax and directed to the following email address. To disable this feature and link a PayPal account, <a href="%s">click here</a>.', 'woocommerce-services' );
				if ( empty( $settings->api_username ) ) {
					$api_creds_text                                = sprintf( $api_creds_template, esc_url( add_query_arg( 'environment', 'live', $reset_link ) ) );
					$form_fields['api_credentials']['description'] = $api_creds_text;
					unset( $form_fields['api_username'], $form_fields['api_password'], $form_fields['api_signature'], $form_fields['api_certificate'] );
				}
				if ( empty( $settings->sandbox_api_username ) ) {
					$api_creds_text                                        = sprintf( $api_creds_template, esc_url( add_query_arg( 'environment', 'sandbox', $reset_link ) ) );
					$form_fields['sandbox_api_credentials']['description'] = $api_creds_text;
					unset( $form_fields['sandbox_api_username'], $form_fields['sandbox_api_password'], $form_fields['sandbox_api_signature'], $form_fields['sandbox_api_certificate'] );
				}
			} else {
				// Provide option to enable request proxying
				$reset_link         = add_query_arg(
					array(
						'reroute_requests' => 'yes',
						'nonce'            => wp_create_nonce( 'reroute_requests' ),
					),
					wc_gateway_ppec()->get_admin_setting_link()
				);
				$api_creds_template = __( 'To authenticate payments with WooCommerce Tax, <a href="%s">click here</a>.', 'woocommerce-services' );
				if ( empty( $settings->api_username ) ) {
					$api_creds_text                                 = sprintf( $api_creds_template, esc_url( add_query_arg( 'environment', 'live', $reset_link ) ) );
					$form_fields['api_credentials']['description'] .= '<br /><br />' . $api_creds_text;
				}
				if ( empty( $settings->sandbox_api_username ) ) {
					$api_creds_text = sprintf( $api_creds_template, esc_url( add_query_arg( 'environment', 'sandbox', $reset_link ) ) );
					$form_fields['sandbox_api_credentials']['description'] .= '<br /><br />' . $api_creds_text;
				}
			}

			return $form_fields;
		}

		/**
		 * Present the "API Subject" setting in a way that's simpler, more comprehensible, and more appropriate to the way it's being used
		 */
		public function adjust_api_subject_form_field( $form_fields ) {
			$api_subject_title                           = __( 'Payment Email', 'woocommerce-services' );
			$form_fields['api_subject']['title']         = $api_subject_title;
			$form_fields['sandbox_api_subject']['title'] = $api_subject_title;

			$api_subject_description                           = __( 'Enter your email address at which to accept payments. You\'ll need to link your own account in order to perform anything other than "sale" transactions.', 'woocommerce-services' );
			$form_fields['api_subject']['description']         = $api_subject_description;
			$form_fields['sandbox_api_subject']['description'] = $api_subject_description;

			$api_subject_placeholder                           = __( 'Required', 'woocommerce-services' );
			$form_fields['api_subject']['placeholder']         = $api_subject_placeholder;
			$form_fields['sandbox_api_subject']['placeholder'] = $api_subject_placeholder;

			return $form_fields;
		}

		/**
		 * Handle reroute_requests setting change
		 */
		public function maybe_set_reroute_requests() {
			if (
				! isset( $_GET['page'] ) || 'wc-settings' !== $_GET['page'] ||
				empty( $_GET['reroute_requests'] ) ||
				empty( $_GET['nonce'] ) ||
				! wp_verify_nonce( $_GET['nonce'], 'reroute_requests' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			) {
				return;
			}

			$settings                   = wc_gateway_ppec()->settings;
			$settings->reroute_requests = 'yes' === $_GET['reroute_requests'] ? 'yes' : 'no';
			if ( isset( $_GET['environment'] ) ) {
				$settings->environment = 'sandbox' === $_GET['environment'] ? 'sandbox' : 'live';
			}
			$settings->save();

			wp_safe_redirect( wc_gateway_ppec()->get_admin_setting_link() );
			exit;
		}
	}
}
