<?php
/**
 * PMPro gateway: Square Hosted Checkout via Payments Square Connect.
 *
 * @package SHC4WC
 */

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

if ( ! class_exists( 'PMProGateway' ) ) {
	return;
}

/**
 * Redirects PMPro checkout to Square payment links for one-time and subscription billing.
 */
class PMProGateway_square_connect extends PMProGateway {

	/** @var bool */
	public static $is_loaded = false;

	/**
	 * @param string|null $gateway Gateway slug.
	 */
	public function __construct( $gateway = null ) {
		$this->gateway             = $gateway ? $gateway : 'square_connect';
		$this->gateway_environment = get_option( 'pmpro_gateway_environment' );
		self::$is_loaded           = true;
		return $this->gateway;
	}

	/**
	 * @return void
	 */
	public static function init() {
		add_filter( 'pmpro_gateways', array( __CLASS__, 'pmpro_gateways' ) );
		add_filter( 'pmpro_payment_options', array( __CLASS__, 'pmpro_payment_options' ) );

		$gateway         = pmpro_getGateway();
		$default_gateway = get_option( 'pmpro_gateway' );

		if ( 'square_connect' === $gateway || 'square_connect' === $default_gateway ) {
			add_filter( 'pmpro_include_payment_information_fields', array( __CLASS__, 'pmpro_include_payment_information_fields' ) );
			add_filter( 'pmpro_required_billing_fields', array( __CLASS__, 'pmpro_required_billing_fields' ) );
			add_action(
				'pmpro_checkout_before_change_membership_level',
				array( __CLASS__, 'pmpro_checkout_before_change_membership_level' ),
				10,
				2
			);
		}

		add_filter( 'pmpro_process_refund_square_connect', array( __CLASS__, 'process_refund' ), 10, 2 );
	}

	/**
	 * @param string $feature Feature slug.
	 * @return bool|string
	 */
	public static function supports( $feature ) {
		$supports = array(
			'payment_method_updates' => false,
			'subscription_sync'      => false,
		);

		return ! empty( $supports[ $feature ] ) ? $supports[ $feature ] : false;
	}

	/**
	 * @param array<string,string> $gateways Registered gateways.
	 * @return array<string,string>
	 */
	public static function pmpro_gateways( $gateways ) {
		$gateways['square_connect'] = __( 'Square Hosted Checkout (Payments Square Connect)', 'payments-connect-square' );
		return $gateways;
	}

	/**
	 * @return string
	 */
	public static function get_description_for_gateway_settings() {
		return esc_html__(
			'Redirect members to Square Hosted Checkout for one-time payments and recurring subscriptions. Uses the same payment link flow as WPForms, Fluent Forms, and WooCommerce in Payments Square Connect.',
			'payments-connect-square'
		);
	}

	/**
	 * @param array<int,string> $options PMPro payment options.
	 * @return array<int,string>
	 */
	public static function pmpro_payment_options( $options ) {
		return $options;
	}

	/**
	 * PMPro only marks built-in gateways as configured; treat Square Connect as ready when connected.
	 *
	 * @param bool $ready Whether PMPro setup is complete.
	 * @return bool
	 */
	public static function pmpro_is_ready( $ready ) {
		global $pmpro_gateway_ready, $pmpro_pages_ready;

		if ( 'square_connect' !== get_option( 'pmpro_gateway' ) ) {
			return $ready;
		}

		if ( get_option( 'pmpro_gateway_environment' ) && SHC4WC_Plugin::is_connected() ) {
			$pmpro_gateway_ready = true;
			return (bool) $pmpro_pages_ready;
		}

		$pmpro_gateway_ready = false;
		return false;
	}

	/**
	 * Gateway-specific settings on PMPro → Settings → Payments → Edit Settings.
	 *
	 * @return void
	 */
	public static function show_settings_fields() {
		$connected    = SHC4WC_Plugin::is_connected();
		$settings     = SHC4WC_Plugin::get_settings();
		$settings_url = admin_url( 'admin.php?page=payments-square-connect' );
		$webhook_url  = SHC4WC_Plugin::public_api_url( 'shc4wc_webhook' );
		$environment  = get_option( 'pmpro_gateway_environment' );
		$square_env   = ! empty( $settings['environment'] ) ? $settings['environment'] : '';
		?>
		<p>
			<?php
			echo wp_kses_post(
				sprintf(
					/* translators: %s: URL to Payments Square Connect settings */
					__( 'Square credentials and location are managed in %s. This gateway redirects members to Square Hosted Checkout for one-time and recurring payments.', 'payments-connect-square' ),
					'<a href="' . esc_url( $settings_url ) . '">' . esc_html__( 'Payments Square Connect', 'payments-connect-square' ) . '</a>'
				)
			);
			?>
		</p>
		<div id="pmpro_square_connect_payment_settings" class="pmpro_section" data-visibility="shown" data-activated="true">
			<div class="pmpro_section_toggle">
				<button class="pmpro_section-toggle-button" type="button" aria-expanded="true">
					<span class="dashicons dashicons-arrow-up-alt2"></span>
					<?php esc_html_e( 'Settings', 'payments-connect-square' ); ?>
				</button>
			</div>
			<div class="pmpro_section_inside">
				<table class="form-table">
					<tbody>
						<tr class="gateway gateway_square_connect">
							<th scope="row" valign="top"><?php esc_html_e( 'Square Connection', 'payments-connect-square' ); ?></th>
							<td>
								<?php if ( $connected ) : ?>
									<span class="dashicons dashicons-yes-alt" style="color:#008a20;"></span>
									<strong><?php esc_html_e( 'Connected', 'payments-connect-square' ); ?></strong>
								<?php else : ?>
									<span class="dashicons dashicons-warning" style="color:#d63638;"></span>
									<strong><?php esc_html_e( 'Not connected', 'payments-connect-square' ); ?></strong>
									<p class="description">
										<a href="<?php echo esc_url( $settings_url ); ?>"><?php esc_html_e( 'Connect Square in Payments Square Connect', 'payments-connect-square' ); ?></a>
									</p>
								<?php endif; ?>
							</td>
						</tr>
						<tr class="gateway gateway_square_connect">
							<th scope="row" valign="top"><?php esc_html_e( 'PMPro Environment', 'payments-connect-square' ); ?></th>
							<td>
								<code><?php echo esc_html( $environment ? $environment : __( 'not set', 'payments-connect-square' ) ); ?></code>
								<?php if ( $environment && $square_env && $environment !== $square_env ) : ?>
									<p class="description" style="color:#d63638;">
										<?php
										echo esc_html(
											sprintf(
												/* translators: 1: PMPro environment, 2: Square Connect environment */
												__( 'Environment mismatch: PMPro is set to %1$s but Square Connect is on %2$s. Use the same environment in both places.', 'payments-connect-square' ),
												$environment,
												$square_env
											)
										);
										?>
									</p>
								<?php else : ?>
									<p class="description"><?php esc_html_e( 'Must match the environment selected in Payments Square Connect (sandbox or live).', 'payments-connect-square' ); ?></p>
								<?php endif; ?>
							</td>
						</tr>
						<tr class="gateway gateway_square_connect">
							<th scope="row" valign="top"><?php esc_html_e( 'Webhook URL', 'payments-connect-square' ); ?></th>
							<td>
								<code><?php echo esc_html( $webhook_url ); ?></code>
								<p class="description">
									<?php
									echo wp_kses_post(
										sprintf(
											/* translators: %s: link to Square Developer Dashboard */
											__( 'Add this URL in the %s so renewals and subscription events update membership status.', 'payments-connect-square' ),
											'<a href="https://developer.squareup.com/apps" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Square Developer Dashboard → Webhooks', 'payments-connect-square' ) . '</a>'
										)
									);
									?>
								</p>
							</td>
						</tr>
					</tbody>
				</table>
			</div>
		</div>
		<?php
	}

	/**
	 * @param bool $include Whether to show default card fields.
	 * @return bool
	 */
	public static function pmpro_include_payment_information_fields( $include ) {
		if ( 'square_connect' !== pmpro_getGateway() ) {
			return $include;
		}
		?>
		<div id="pmpro_payment_information_fields" class="pmpro_checkout-field">
			<h3>
				<span class="pmpro_checkout-h3-name"><?php esc_html_e( 'Payment Information', 'payments-connect-square' ); ?></span>
			</h3>
			<p><?php esc_html_e( 'After you submit this form, you will be redirected to Square to pay securely. Recurring memberships are billed automatically by Square on your membership billing cycle.', 'payments-connect-square' ); ?></p>
		</div>
		<?php
		return false;
	}

	/**
	 * @param array<string,string> $fields Required billing fields.
	 * @return array<string,string>
	 */
	public static function pmpro_required_billing_fields( $fields ) {
		unset( $fields['CardType'], $fields['AccountNumber'], $fields['ExpirationMonth'], $fields['ExpirationYear'], $fields['CVV'] );
		return $fields;
	}

	/**
	 * Redirect to Square after PMPro validates checkout and creates the pending order.
	 *
	 * @param int         $user_id User id.
	 * @param MemberOrder $morder  PMPro order.
	 * @return void
	 */
	public static function pmpro_checkout_before_change_membership_level( $user_id, $morder ) {
		unset( $user_id );

		if ( empty( $morder ) || 'square_connect' !== $morder->gateway ) {
			return;
		}

		if ( in_array( $morder->status, array( 'success', 'free' ), true ) ) {
			return;
		}

		$redirect = get_transient( 'shc4wc_pmpro_redirect_' . sanitize_text_field( (string) $morder->code ) );
		if ( ! $redirect ) {
			return;
		}

		delete_transient( 'shc4wc_pmpro_redirect_' . sanitize_text_field( (string) $morder->code ) );

		// Square hosted checkout is off-site; wp_safe_redirect() would fall back to wp-admin.
		wp_redirect( esc_url_raw( $redirect ) ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect -- Square hosted checkout.
		exit;
	}

	/**
	 * Build the Square hosted checkout session; redirect happens in the hook above.
	 *
	 * @param MemberOrder $order PMPro order.
	 * @return bool
	 */
	public function process( &$order ) {
		if ( empty( $order->code ) ) {
			$order->code = $order->getRandomCode();
		}

		$order->gateway = 'square_connect';
		$order->payment_type = 'Square Hosted Checkout';

		$started = SHC4WC_PMPro::start_checkout( $order );
		if ( is_wp_error( $started ) ) {
			$order->error      = $started->get_error_message();
			$order->shorterror = $order->error;
			return false;
		}

		if ( true === $started && 'success' === $order->status ) {
			return true;
		}

		// Redirect immediately; membership is granted only after Square return/webhook.
		self::pmpro_checkout_before_change_membership_level( $order->user_id, $order );

		$order->error      = __( 'Unable to redirect to Square checkout.', 'payments-connect-square' );
		$order->shorterror = $order->error;
		return false;
	}

	/**
	 * @param PMPro_Subscription $subscription PMPro subscription.
	 * @return bool
	 */
	public function cancel_subscription( $subscription ) {
		if ( ! is_object( $subscription ) || ! method_exists( $subscription, 'get_subscription_transaction_id' ) ) {
			return false;
		}

		$transaction_id = sanitize_text_field( (string) $subscription->get_subscription_transaction_id() );
		if ( '' === $transaction_id ) {
			return false;
		}

		$api      = new SHC4WC_API( SHC4WC_Plugin::get_settings() );
		$response = $api->request(
			'POST',
			'/v2/subscriptions/' . rawurlencode( $transaction_id ) . '/cancel',
			array()
		);

		return ! is_wp_error( $response );
	}

	/**
	 * @param bool        $success Whether refund already succeeded.
	 * @param MemberOrder $order   PMPro order.
	 * @return bool
	 */
	public static function process_refund( $success, $order ) {
		if ( $success || empty( $order->payment_transaction_id ) || 0 === strpos( (string) $order->payment_transaction_id, 'square_hosted_' ) ) {
			return $success;
		}

		global $pmpro_currency;

		$api = new SHC4WC_API( SHC4WC_Plugin::get_settings() );
		$response = $api->create_refund(
			$order->payment_transaction_id,
			(float) $order->total,
			$pmpro_currency ? $pmpro_currency : 'USD',
			'shc4wc-pmpro-refund-' . (int) $order->id
		);

		return ! is_wp_error( $response );
	}
}

// Register before PMPro runs pmpro_is_ready() on init priority 10.
add_filter( 'pmpro_is_ready', array( 'PMProGateway_square_connect', 'pmpro_is_ready' ) );
