<?php
/**
 * Privacy/GDPR related functionality which ties into WordPress functionality.
 *
 * @author   Prospress
 * @category Class
 * @package  WooCommerce Subscriptions\Privacy
 * @version  1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

class WCS_Privacy extends WC_Abstract_Privacy {

	/**
	 * Background updater to process personal data removal from subscriptions and related orders.
	 *
	 * @var WCS_Privacy_Background_Updater
	 */
	protected static $background_process;

	/**
	 * A flag which is set when WC is doing a user inactivity cleanup.
	 * Used to exclude subscription customers from the inactive user query.
	 *
	 * @var bool
	 */
	protected static $doing_user_inactivity_query = false;

	/**
	 * WCS_Privacy constructor.
	 */
	public function __construct() {
		if ( ! self::$background_process ) {
			self::$background_process = new WCS_Privacy_Background_Updater();
		}

		parent::__construct();

		add_action( 'init', array( $this, 'register_erasers_exporters' ) );
	}

	/**
	 * Register erasers and exporters.
	 */
	public function register_erasers_exporters() {
		$this->name = __( 'WooCommerce Subscriptions', 'woocommerce-subscriptions' );

		// Add our exporters and erasers.
		$this->add_exporter( 'woocommerce-subscriptions-data', __( 'Subscriptions Data', 'woocommerce-subscriptions' ), array( 'WCS_Privacy_Exporters', 'subscription_data_exporter' ) );
		$this->add_eraser( 'woocommerce-subscriptions-data', __( 'Subscriptions Data', 'woocommerce-subscriptions' ), array( 'WCS_Privacy_Erasers', 'subscription_data_eraser' ) );
	}

	/**
	 * Attach callbacks.
	 */
	public function init() {
		parent::init();
		self::$background_process->init();

		add_filter( 'woocommerce_subscription_bulk_actions', array( __CLASS__, 'add_privacy_bulk_action' ) );
		add_action( 'load-edit.php', array( __CLASS__, 'process_bulk_action' ) );
		add_action( 'woocommerce_remove_subscription_personal_data', array( 'WCS_Privacy_Erasers', 'remove_subscription_personal_data' ) );
		add_action( 'admin_notices', array( __CLASS__, 'bulk_admin_notices' ) );

		add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_caveat_to_order_data_retention_settings' ) );
		add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_subscription_data_retention_settings' ) );

		// Attach callbacks to prevent subscription related orders being trashed or anonymized
		add_filter( 'woocommerce_trash_pending_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
		add_filter( 'woocommerce_trash_failed_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
		add_filter( 'woocommerce_trash_cancelled_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );
		add_filter( 'woocommerce_anonymize_completed_orders_query_args', array( __CLASS__, 'remove_subscription_orders_from_anonymization_query' ) );

		add_action( 'woocommerce_cleanup_personal_data', array( $this, 'queue_cleanup_personal_data' ) );

		// Hook in late so there is less opportunity for our flag to affect other user queries called on this hook.
		add_filter( 'woocommerce_delete_inactive_account_roles', array( __CLASS__, 'flag_subscription_user_exclusion_from_query' ), 1000 );
		add_action( 'pre_get_users', array( __CLASS__, 'maybe_exclude_subscription_customers' ) );
		add_filter( 'woocommerce_account_settings', array( __CLASS__, 'add_inactive_user_retention_note' ) );

		add_action( 'handle_bulk_actions-woocommerce_page_wc-orders--shop_subscription', [ __CLASS__, 'handle_privacy_bulk_actions' ], 10, 3 );
	}

	/**
	 * Spawn events for subscription cleanup.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 */
	public function queue_cleanup_personal_data() {
		self::$background_process->schedule_ended_subscription_anonymization();
	}

	/**
	 * Add privacy policy content for the privacy policy page.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 */
	public function get_privacy_message() {
		return '' .
		'<p>' . __( 'By using WooCommerce Subscriptions, you may be storing personal data and depending on which third-party payment processors you’re using to take subscription payments, you may be sharing personal data with external sources.', 'woocommerce-subscriptions' ) . '</p>' .
		// translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation.
		'<h3>' . __( 'What we collect and store', 'woocommerce-subscriptions' ) . '</h3>' .
		'<p>' . __( 'For the purposes of processing recurring subscription payments, we store the customer\'s name, billing address, shipping address, email address, phone number and credit card/payment details.', 'woocommerce-subscriptions' ) . '</p>' .
		'<h3>' . __( 'What we share with others', 'woocommerce-subscriptions' ) . '</h3>' .
		'<p>' . __( 'What personal information your store shares with external sources depends on which third-party payment processor plugins you are using to collect subscription payments. We recommend that you consult with their privacy policies to inform this section of your privacy policy.', 'woocommerce-subscriptions' ) . '</p>' .
		// translators: placeholders are opening and closing link tags, linking to additional privacy policy documentation.
		'<p>' . sprintf( __( 'If you are using PayPal Standard or PayPal Reference transactions please see the %1$sPayPal Privacy Policy%2$s for more details.', 'woocommerce-subscriptions' ), '<a href="https://www.paypal.com/us/webapps/mpp/ua/privacy-full">', '</a>' ) . '</p>';
	}

	/**
	 * Adds the option to remove personal data from subscription via a bulk action.
	 *
	 * @since 5.2.0
	 *
	 * @param array $bulk_actions Subscription bulk actions.
	 *
	 * @return array
	 */
	public static function add_privacy_bulk_action( $bulk_actions ) {
		$bulk_actions['wcs_remove_personal_data'] = __( 'Cancel and remove personal data', 'woocommerce-subscriptions' );
		return $bulk_actions;
	}

	/**
	 * Handles the Remove Personal Data bulk action requests for Subscriptions.
	 *
	 * @param string $redirect_url     The default URL to redirect to after handling the bulk action request.
	 * @param string $action           The action to take against the list of subscriptions.
	 * @param array  $subscription_ids The list of subscription to run the action against.
	 */
	public static function handle_privacy_bulk_actions( $redirect_url, $action, $subscription_ids ) {
		if ( 'wcs_remove_personal_data' !== $action ) {
			return $redirect_url;
		}

		$changed       = 0;
		$sendback_args = [
			'bulk_action' => 'wcs_remove_personal_data',
			'ids'         => join( ',', $subscription_ids ),
			'error_count' => 0,
		];

		foreach ( $subscription_ids as $subscription_id ) {
			$subscription = wcs_get_subscription( $subscription_id );

			if ( is_a( $subscription, 'WC_Subscription' ) ) {
				do_action( 'woocommerce_remove_subscription_personal_data', $subscription );
				$changed++;
			}
		}

		$sendback_args['changed'] = $changed;
		$sendback                 = add_query_arg( $sendback_args, $redirect_url );

		return esc_url_raw( $sendback );
	}

	/**
	 * Process the request to delete personal data from subscriptions via admin bulk action.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 */
	public static function process_bulk_action() {
		/**
		 * We only want to deal with shop_subscription bulk actions.
		 *
		 * Note: The nonce checks are ignored below as we are validating the request before returning.
		 */
		if ( ! isset( $_REQUEST['post_type'] ) || 'shop_subscription' !== $_REQUEST['post_type'] || ! isset( $_REQUEST['post'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		check_admin_referer( 'bulk-posts' );

		$action = '';

		if ( isset( $_REQUEST['action'] ) && -1 !== $_REQUEST['action'] ) {
			$action = wc_clean( wp_unslash( $_REQUEST['action'] ) );
		} elseif ( isset( $_REQUEST['action2'] ) && -1 !== $_REQUEST['action2'] ) {
			$action = wc_clean( wp_unslash( $_REQUEST['action2'] ) );
		}

		$subscription_ids  = array_map( 'absint', (array) $_REQUEST['post'] );
		$base_redirect_url = wp_get_referer() ? wp_get_referer() : '';

		$redirect_url = self::handle_privacy_bulk_actions( $base_redirect_url, $action, $subscription_ids );

		wp_safe_redirect( $redirect_url );
		exit();
	}

	/**
	 * Add admin notice after processing personal data removal bulk action.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 */
	public static function bulk_admin_notices() {
		// Nonce verification is not required here because we're just displaying an admin notice after a verified request was made.
		if ( ! isset( $_REQUEST['bulk_action'] ) || ! 'wcs_remove_personal_data' === wc_clean( wp_unslash( $_REQUEST['bulk_action'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}

		if ( wcs_is_custom_order_tables_usage_enabled() ) {
			$current_screen             = get_current_screen();
			$is_subscription_list_table = $current_screen && wcs_get_page_screen_id( 'shop_subscription' ) === $current_screen->id;
		} else {
			global $post_type, $pagenow;
			$is_subscription_list_table = 'edit.php' === $pagenow && 'shop_subscription' === $post_type;
		}

		// Bail out if not on shop subscription list page.
		if ( ! $is_subscription_list_table ) {
			return;
		}

		$changed = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0;
		// translators: %d: number of subscriptions affected.
		$message = sprintf( _n( 'Removed personal data from %d subscription.', 'Removed personal data from %d subscriptions.', $changed, 'woocommerce-subscriptions' ), number_format_i18n( $changed ) );
		echo '<div class="updated"><p>' . esc_html( $message ) . '</p></div>';
	}

	/**
	 * Add a note to WC Personal Data Retention settings explaining that subscription orders aren't affected.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 * @param array $settings WooCommerce Account and Privacy settings.
	 * @return array Account and Privacy settings.
	 */
	public static function add_caveat_to_order_data_retention_settings( $settings ) {
		if ( ! is_array( $settings ) ) {
			return $settings;
		}

		foreach ( $settings as &$setting ) {
			if ( isset( $setting['id'], $setting['type'] ) && 'personal_data_retention' === $setting['id'] && 'title' === $setting['type'] ) {
				// translators: placeholders are opening and closing tags.
				$note            = sprintf( __( '%1$sNote:%2$s Orders which are related to subscriptions will not be included in the orders affected by these settings.', 'woocommerce-subscriptions' ), '<b>', '</b>' );
				$setting['desc'] = isset( $setting['desc'] ) ? $setting['desc'] . '<br>' . $note : $note;
			}
		}

		return $settings;
	}

	/**
	 * Add admin setting to turn subscription data removal when processing erasure requests on or off.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 * @param array $settings WooCommerce Account and Privacy settings.
	 * @return array Account and Privacy settings.
	 */
	public static function add_subscription_data_retention_settings( $settings ) {
		if ( ! is_array( $settings ) ) {
			return $settings;
		}

		$erasure_text = esc_html__( 'account erasure request', 'woocommerce-subscriptions' );
		if ( current_user_can( 'manage_privacy_options' ) ) {
			$erasure_text = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'tools.php?page=remove_personal_data' ) ), $erasure_text );
		}

		WC_Subscriptions_Admin::insert_setting_after( $settings, 'woocommerce_erasure_request_removes_order_data', array(
			'desc'          => __( 'Remove personal data from subscriptions', 'woocommerce-subscriptions' ),
			/* Translators: %s URL to erasure request screen. */
			'desc_tip'      => sprintf( __( 'When handling an %s, should personal data within subscriptions be retained or removed?', 'woocommerce-subscriptions' ), $erasure_text ),
			'id'            => 'woocommerce_erasure_request_removes_subscription_data',
			'type'          => 'checkbox',
			'default'       => 'no',
			'checkboxgroup' => '',
			'autoload'      => false,
		) );

		WC_Subscriptions_Admin::insert_setting_after( $settings, 'woocommerce_anonymize_completed_orders', array(
			'title'       => __( 'Retain ended subscriptions', 'woocommerce-subscriptions' ),
			'desc_tip'    => __( 'Retain ended subscriptions and their related orders for a specified duration before anonymizing the personal data within them.', 'woocommerce-subscriptions' ),
			'id'          => 'woocommerce_anonymize_ended_subscriptions',
			'type'        => 'relative_date_selector',
			'placeholder' => __( 'N/A', 'woocommerce-subscriptions' ),
			'default'     => array(
				'number' => '',
				'unit'   => 'months',
			),
			'autoload'    => false,
		) );

		return $settings;
	}

	/**
	 * Remove subscription related order types from the order anonymization query.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 * @param  array $query_args @see wc_get_orders() args.
	 * @return array The args used to get orders to anonymize.
	 */
	public static function remove_subscription_orders_from_anonymization_query( $query_args ) {
		if ( ! is_array( $query_args ) ) {
			return $query_args;
		}

		$query_args['subscription_parent']      = false;
		$query_args['subscription_renewal']     = false;
		$query_args['subscription_switch']      = false;
		$query_args['subscription_resubscribe'] = false;

		return $query_args;
	}

	/**
	 * Add a note to the inactive user data retention setting noting that users with a subscription are excluded.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
	 * @param array $settings WooCommerce Account and Privacy settings.
	 * @return array Account and Privacy settings.
	 */
	public static function add_inactive_user_retention_note( $settings ) {
		foreach ( $settings as &$setting ) {
			if ( isset( $setting['id'], $setting['desc_tip'] ) && 'woocommerce_delete_inactive_accounts' === $setting['id'] ) {
				$setting['desc_tip'] .= ' ' . __( 'Customers with a subscription are excluded from this setting.', 'woocommerce-subscriptions' );
				break;
			}
		}

		return $settings;
	}

	/**
	 * Set a flag to record inactive user account deletion.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
	 * @param  array $user_roles The user roles included in the inactive user query.
	 * @return array
	 */
	public static function flag_subscription_user_exclusion_from_query( $user_roles ) {
		self::$doing_user_inactivity_query = true;
		return $user_roles;
	}

	/**
	 * Exclude customers who have subscriptions from the inactive user cleanup query.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.4
	 * @param WP_User_Query $user_query
	 */
	public static function maybe_exclude_subscription_customers( $user_query ) {
		if ( ! self::$doing_user_inactivity_query ) {
			return;
		}

		$user_query->set( 'exclude', array_merge(
			(array) $user_query->get( 'exclude' ),
			WC_Data_Store::load( 'subscription' )->get_subscription_customer_ids()
		) );

		self::$doing_user_inactivity_query = false;
	}

	/* Deprecated Functions */

	/**
	 * Add the option to remove personal data from subscription via a bulk action.
	 *
	 * @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.20
	 * @param array $bulk_actions Subscription bulk actions.
	 */
	public static function add_remove_personal_data_bulk_action( $bulk_actions ) {
		wcs_deprecated_function( __METHOD__, 'subscriptions-core 5.2.0', 'WCS_Privacy_Exporters::add_privacy_bulk_action' );
		$bulk_actions['remove_personal_data'] = __( 'Cancel and remove personal data', 'woocommerce-subscriptions' );

		return $bulk_actions;
	}
}
