<?php
/**
 * The blocks module.
 *
 * @package WooCommerce\PayPalCommerce\Blocks
 */

declare(strict_types=1);

namespace WooCommerce\PayPalCommerce\Blocks;

use Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType;
use WC_AJAX;
use WooCommerce\PayPalCommerce\Blocks\Endpoint\UpdateShippingEndpoint;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButtonInterface;
use WooCommerce\PayPalCommerce\Session\Cancellation\CancelController;
use WooCommerce\PayPalCommerce\Session\Cancellation\CancelView;
use WooCommerce\PayPalCommerce\Session\SessionHandler;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Helper\SettingsStatus;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcSubscriptions\Helper\SubscriptionHelper;

/**
 * Class PayPalPaymentMethod
 */
class PayPalPaymentMethod extends AbstractPaymentMethodType {
	/**
	 * The URL of this module.
	 *
	 * @var string
	 */
	private $module_url;

	/**
	 * The assets version.
	 *
	 * @var string
	 */
	private $version;

	/**
	 * The smart button script loading handler.
	 *
	 * @var SmartButtonInterface|callable
	 */
	private $smart_button;

	/**
	 * The settings.
	 *
	 * @var Settings
	 */
	private $plugin_settings;

	/**
	 * The Settings status helper.
	 *
	 * @var SettingsStatus
	 */
	protected $settings_status;

	/**
	 * The WC gateway.
	 *
	 * @var PayPalGateway
	 */
	private $gateway;

	/**
	 * Whether the final review is enabled.
	 *
	 * @var bool
	 */
	private $final_review_enabled;

	/**
	 * The cancellation view.
	 *
	 * @var CancelView
	 */
	private $cancellation_view;

	/**
	 * The Session handler.
	 *
	 * @var SessionHandler
	 */
	private $session_handler;

	/**
	 * The Subscription Helper.
	 *
	 * @var SubscriptionHelper
	 */
	private $subscription_helper;

	/**
	 * Whether to create a non-express method with the standard "Place order" button.
	 *
	 * @var bool
	 */
	protected $add_place_order_method;

	/**
	 * Whether to use the standard "Place order" button instead of PayPal buttons.
	 *
	 * @var bool
	 */
	protected $use_place_order;

	/**
	 * The text for the standard "Place order" button.
	 *
	 * @var string
	 */
	protected $place_order_button_text;

	/**
	 * The text for additional "Place order" description.
	 *
	 * @var string
	 */
	protected $place_order_button_description;

	/**
	 * All existing funding sources for PayPal buttons.
	 *
	 * @var array
	 */
	private $all_funding_sources;

	/**
	 * Whether shipping details must be collected during checkout; i.e. paying for physical goods?
	 *
	 * @var bool
	 */
	private $need_shipping;

	/**
	 * Assets constructor.
	 *
	 * @param string                        $module_url The url of this module.
	 * @param string                        $version    The assets version.
	 * @param SmartButtonInterface|callable $smart_button The smart button script loading handler.
	 * @param Settings                      $plugin_settings The settings.
	 * @param SettingsStatus                $settings_status The Settings status helper.
	 * @param PayPalGateway                 $gateway The WC gateway.
	 * @param bool                          $final_review_enabled Whether the final review is enabled.
	 * @param CancelView                    $cancellation_view The cancellation view.
	 * @param SessionHandler                $session_handler The Session handler.
	 * @param SubscriptionHelper            $subscription_helper The subscription helper.
	 * @param bool                          $add_place_order_method Whether to create a non-express method with the standard "Place order" button.
	 * @param bool                          $use_place_order Whether to use the standard "Place order" button instead of PayPal buttons.
	 * @param string                        $place_order_button_text The text for the standard "Place order" button.
	 * @param string                        $place_order_button_description The text for additional "Place order" description.
	 * @param array                         $all_funding_sources All existing funding sources for PayPal buttons.
	 * @param bool                          $need_shipping Whether shipping details are required for the purchase.
	 */
	public function __construct(
		string $module_url,
		string $version,
		$smart_button,
		Settings $plugin_settings,
		SettingsStatus $settings_status,
		PayPalGateway $gateway,
		bool $final_review_enabled,
		CancelView $cancellation_view,
		SessionHandler $session_handler,
		SubscriptionHelper $subscription_helper,
		bool $add_place_order_method,
		bool $use_place_order,
		string $place_order_button_text,
		string $place_order_button_description,
		array $all_funding_sources,
		bool $need_shipping
	) {
		$this->name                           = PayPalGateway::ID;
		$this->module_url                     = $module_url;
		$this->version                        = $version;
		$this->smart_button                   = $smart_button;
		$this->plugin_settings                = $plugin_settings;
		$this->settings_status                = $settings_status;
		$this->gateway                        = $gateway;
		$this->final_review_enabled           = $final_review_enabled;
		$this->cancellation_view              = $cancellation_view;
		$this->session_handler                = $session_handler;
		$this->subscription_helper            = $subscription_helper;
		$this->add_place_order_method         = $add_place_order_method;
		$this->use_place_order                = $use_place_order;
		$this->place_order_button_text        = $place_order_button_text;
		$this->place_order_button_description = $place_order_button_description;
		$this->all_funding_sources            = $all_funding_sources;
		$this->need_shipping                  = $need_shipping;
	}

	/**
	 * {@inheritDoc}
	 */
	public function initialize() {  }

	/**
	 * {@inheritDoc}
	 */
	public function is_active() {
		// Do not load when definitely not needed,
		// but we still need to check the locations later and handle in JS
		// because has_block cannot be called here (too early).
		return $this->plugin_settings->has( 'enabled' ) && $this->plugin_settings->get( 'enabled' );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_payment_method_script_handles() {
		wp_register_script(
			'ppcp-checkout-block',
			trailingslashit( $this->module_url ) . 'assets/js/checkout-block.js',
			array(),
			$this->version,
			true
		);

		return array( 'ppcp-checkout-block' );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_payment_method_data() {
		$script_data = $this->smart_button()->script_data();

		if ( isset( $script_data['continuation'] ) ) {
			$url = add_query_arg( array( CancelController::NONCE => wp_create_nonce( CancelController::NONCE ) ), wc_get_checkout_url() );

			$script_data['continuation']['cancel'] = array(
				'html' => $this->cancellation_view->render_session_cancellation( $url, $this->session_handler->funding_source() ),
			);

			$order = $this->session_handler->order();
			if ( $order ) {
				$script_data['continuation']['order'] = $order->to_array();
			}
		}

		$funding_sources = array();
		if ( ! $this->is_editing() ) {
			$disabled_funding_sources = explode( ',', $script_data['url_params']['disable-funding'] ?? '' ) ?: array();
			$funding_sources          = array_values(
				array_diff(
					array_keys( $this->all_funding_sources ),
					$disabled_funding_sources
				)
			);
		}

		$smart_buttons_enabled = ! $this->use_place_order
			&& $this->settings_status->is_smart_button_enabled_for_location( $script_data['context'] ?? 'block-checkout' );
		$place_order_enabled   = ( $this->use_place_order || $this->add_place_order_method )
			&& ! $this->subscription_helper->cart_contains_subscription();

		return array(
			'id'                          => $this->gateway->id,
			'title'                       => $this->gateway->title,
			'icon'                        => array(
				array(
					'id'  => 'paypal',
					'alt' => 'PayPal',
					'src' => $this->gateway->icon,
				),
			),
			'description'                 => $this->gateway->description,
			'smartButtonsEnabled'         => $smart_buttons_enabled,
			'placeOrderEnabled'           => $place_order_enabled,
			'fundingSource'               => $this->session_handler->funding_source(),
			'finalReviewEnabled'          => $this->final_review_enabled,
			'placeOrderButtonText'        => $this->place_order_button_text,
			'placeOrderButtonDescription' => $this->place_order_button_description,
			'enabledFundingSources'       => $funding_sources,
			'ajax'                        => array(
				'update_shipping' => array(
					'endpoint' => WC_AJAX::get_endpoint( UpdateShippingEndpoint::ENDPOINT ),
					'nonce'    => wp_create_nonce( UpdateShippingEndpoint::nonce() ),
				),
			),
			'scriptData'                  => $script_data,
			'needShipping'                => $this->need_shipping,
		);
	}

	/**
	 * Checks if it is the block editing mode.
	 */
	private function is_editing(): bool {
		if ( ! function_exists( 'get_current_screen' ) ) {
			return false;
		}
		$screen = get_current_screen();
		return $screen && $screen->is_block_editor();
	}

	/**
	 * The smart button.
	 *
	 * @return SmartButtonInterface
	 */
	private function smart_button(): SmartButtonInterface {
		if ( $this->smart_button instanceof SmartButtonInterface ) {
			return $this->smart_button;
		}

		if ( is_callable( $this->smart_button ) ) {
			$this->smart_button = ( $this->smart_button )();
		}

		return $this->smart_button;
	}
}
