<?php
/**
 * A class that handles displaying an "Exit Interview" for users deactivating the plugin.
 *
 * @since 1.0.0
 *
 * @package StellarWP\Telemetry
 *
 * @license GPL-2.0-or-later
 * Modified using Strauss.
 * @see https://github.com/BrianHenryIE/strauss
 */

namespace RCP\StellarWP\Telemetry\Exit_Interview;

use RCP\StellarWP\Telemetry\Contracts\Abstract_Subscriber;
use RCP\StellarWP\Telemetry\Config;
use RCP\StellarWP\Telemetry\Opt_In\Status;
use RCP\StellarWP\Telemetry\Telemetry\Telemetry;

/**
 * A class that handles displaying an "Exit Interview" for users deactivating the plugin.
 *
 * @since 1.0.0
 *
 * @package StellarWP\Telemetry
 */
class Exit_Interview_Subscriber extends Abstract_Subscriber {

	const AJAX_ACTION = 'exit-interview';

	/**
	 * @inheritDoc
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function register(): void {

		// If the site is not opted in, don't enqueue the Exit Interview modal.
		if ( ! $this->container->get( Status::class )->is_active() ) {
			return;
		}

		add_action( 'admin_footer', [ $this, 'render_exit_interview' ] );
		add_action( 'wp_ajax_' . self::AJAX_ACTION, [ $this, 'ajax_exit_interview' ] );

		// Implement the exit interview trigger for each registerred plugin.
		foreach ( Config::get_all_stellar_slugs() as $basename ) {
			add_filter( 'network_admin_plugin_action_links_' . $basename, [ $this, 'plugin_action_links' ], 10, 2 );
			add_filter( 'plugin_action_links_' . $basename, [ $this, 'plugin_action_links' ], 10, 2 );
		}
	}

	/**
	 * Possibly renders the exit interview if the user is on the plugins list page.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function render_exit_interview() {
		global $pagenow;

		if ( 'plugins.php' === $pagenow ) {
			// Swap key/values since we need to map stellar slugs by plugin basename.
			$stellar_slugs = array_flip( Config::get_all_stellar_slugs() );
			$plugins       = get_plugins();
			foreach ( $plugins as $slug => $data ) {
				if ( key_exists( $slug, $stellar_slugs ) ) {
					$this->container->get( Template::class )->maybe_render( $stellar_slugs[ $slug ] );
				}
			}
		}
	}

	/**
	 * Handles the ajax request for submitting "Exit Interivew" form data.
	 *
	 * @since 1.0.0
	 * @since 2.3.4 - Added user capability check.
	 *
	 * @return void
	 */
	public function ajax_exit_interview() {

		// Check sent data before we do any database checks for faster failures.
		$uninstall_reason_id = filter_input( INPUT_POST, 'uninstall_reason_id', FILTER_SANITIZE_SPECIAL_CHARS );
		$uninstall_reason_id = ! empty( $uninstall_reason_id ) ? $uninstall_reason_id : false;
		if ( ! $uninstall_reason_id ) {
			wp_send_json_error( 'No reason id provided' );
		}

		$uninstall_reason = filter_input( INPUT_POST, 'uninstall_reason', FILTER_SANITIZE_SPECIAL_CHARS );
		$uninstall_reason = ! empty( $uninstall_reason ) ? $uninstall_reason : false;
		if ( ! $uninstall_reason ) {
			wp_send_json_error( 'No reason provided' );
		}

		$plugin_slug = filter_input( INPUT_POST, 'plugin_slug', FILTER_SANITIZE_SPECIAL_CHARS );

		$comment = filter_input( INPUT_POST, 'comment', FILTER_SANITIZE_SPECIAL_CHARS );
		$comment = ! empty( $comment ) ? $comment : '';

		// Validate nonce.
		$nonce = filter_input( INPUT_POST, 'nonce', FILTER_SANITIZE_SPECIAL_CHARS );
		$nonce = ! empty( $nonce ) ? $nonce : '';

		if ( ! wp_verify_nonce( $nonce, self::AJAX_ACTION ) ) {
			wp_send_json_error( 'Invalid nonce' );
		}

		// Sent data validated, check if the user has the necessary permissions.
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( 'User does not have proper permissions to modify plugins' );
		}

		$telemetry = $this->container->get( Telemetry::class );
		$telemetry->send_uninstall( $plugin_slug, $uninstall_reason_id, $uninstall_reason, $comment );

		wp_send_json_success();
	}

	/**
	 * Adds an <i> element after the "deactivate" link on the plugin list table so that it can be targeted by JS to trigger the interview modal.
	 *
	 * The deactivation is deferred to the modal displayed.
	 *
	 * @param array  $links        The links of the plugin in the plugin list.
	 * @param string $plugin_file The plugin file of the current plugin in the list.
	 *
	 * @since 1.0.0
	 *
	 * @return array
	 */
	public function plugin_action_links( $links, $plugin_file ) {

		$stellar_slug = '';

		foreach ( Config::get_all_stellar_slugs() as $slug => $basename ) {
			if ( plugin_basename( $plugin_file ) === $basename ) {
				$stellar_slug = $slug;
				continue;
			}
		}

		$passed_deactivate = false;
		$deactivate_link   = '';
		$before_deactivate = [];
		$after_deactivate  = [];

		foreach ( $links as $key => $link ) {
			if ( 'deactivate' === $key ) {
				$deactivate_link   = $link;
				$passed_deactivate = true;
				continue;
			}

			if ( ! $passed_deactivate ) {
				$before_deactivate[ $key ] = $link;
			} else {
				$after_deactivate[ $key ] = $link;
			}
		}

		if ( ! empty( $deactivate_link ) ) {
			$deactivate_link .= '<i class="telemetry-plugin-slug" data-plugin-slug="' . $stellar_slug . '"></i>';

			// Append deactivation link.
			$before_deactivate['deactivate'] = $deactivate_link;
		}

		return array_merge( $before_deactivate, $after_deactivate );
	}
}
