<?php
/**
 * PK Core - the "a new plugin is using your Site Profile" notice.
 *
 * When a PublisherKits plugin becomes active on a site that already has a
 * profile, the operator should be TOLD that their existing answers are already
 * being used - and asked only about the gaps that new plugin specifically cares
 * about. Never sent back through a setup wizard to retype what they answered
 * for something else. That experience is what makes a suite feel like a suite
 * rather than nine plugins in a trenchcoat.
 *
 * THREE RULES, each of which stops a plausible annoyance:
 *
 * 1. NEVER on a fresh site. If the profile is empty this is a first install and
 *    the wizard owns that moment - two prompts competing for the same click is
 *    worse than either alone.
 * 2. NAME ONLY WHAT THAT PLUGIN READS. Not the whole profile, and never a key
 *    it merely plans to read. The gap list comes from the consumer matrix's
 *    measured `consumes`, so the notice cannot ask for something that would sit
 *    unused.
 * 3. ONCE PER PLUGIN, EVER. Announcing on every page load is how a notice
 *    teaches people to dismiss without reading.
 *
 * @package PublisherKits\Core
 * @since   0.10.0
 */

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

if ( ! class_exists( 'PKCORE_Notices' ) ) {

	/**
	 * Class PKCORE_Notices
	 *
	 * @since 0.10.0
	 */
	class PKCORE_Notices {

		const OPTION = 'pkcore_announced_consumers';

		/**
		 * Which consumers deserve an announcement right now.
		 *
		 * PURE apart from the two option reads, so the decision can be tested
		 * without WordPress.
		 *
		 * @param array    $active_handles Handles currently active.
		 * @param array    $announced      Handles already announced.
		 * @param bool     $profile_has_answers Whether the profile holds anything.
		 * @return string[] Handles to announce.
		 */
		public static function decide( $active_handles, $announced, $profile_has_answers ) {
			if ( ! $profile_has_answers ) {
				return array(); // Rule 1: the wizard owns a fresh site.
			}
			$announced = is_array( $announced ) ? $announced : array();
			$out       = array();
			foreach ( (array) $active_handles as $handle ) {
				if ( ! in_array( $handle, $announced, true ) ) {
					$out[] = $handle;
				}
			}
			return $out;
		}

		/**
		 * Register.
		 *
		 * @return void
		 */
		public static function init() {
			add_action( 'admin_notices', array( __CLASS__, 'maybe_render' ) );
			add_action( 'admin_post_pkcore_dismiss_consumer', array( __CLASS__, 'handle_dismiss' ) );
		}

		/**
		 * Whether the profile holds any answer at all.
		 *
		 * @return bool
		 */
		private static function profile_has_answers() {
			return class_exists( 'PKCORE_Profile' ) && PKCORE_Profile::is_populated();
		}

		/**
		 * Active consumer handles.
		 *
		 * @return string[]
		 */
		private static function active_handles() {
			$out = array();
			foreach ( PKCORE_Consumers::all() as $handle => $spec ) {
				if ( PKCORE_Consumers::is_active( $handle ) ) {
					$out[] = $handle;
				}
			}
			return $out;
		}

		/**
		 * Render at most ONE notice - the first unannounced consumer.
		 *
		 * One at a time deliberately: activating four plugins at once should not
		 * produce four stacked notices the operator scrolls past.
		 *
		 * @return void
		 */
		public static function maybe_render() {
			if ( ! current_user_can( 'manage_options' ) ) {
				return;
			}

			$pending = self::decide(
				self::active_handles(),
				get_option( self::OPTION, array() ),
				self::profile_has_answers()
			);
			if ( empty( $pending ) ) {
				return;
			}

			$handle = reset( $pending );
			$all    = PKCORE_Consumers::all();
			if ( ! isset( $all[ $handle ] ) ) {
				return;
			}
			$label = $all[ $handle ]['label'];
			$gaps  = PKCORE_Consumers::unanswered_for( $handle );

			echo '<div class="notice notice-info is-dismissible pkcore-consumer-notice">';

			echo '<p><strong>' . esc_html(
				sprintf(
					/* translators: %s: plugin name. */
					__( '%s is already using your Site Profile.', 'publisherkits-socialpromoter' ),
					$label
				)
			) . '</strong></p>';

			if ( empty( $gaps ) ) {
				// Everything it reads is answered. Say so and get out of the way -
				// this is the good case and it deserves one line, not a task.
				echo '<p>' . esc_html__( 'Everything it needs is already filled in. Nothing to do.', 'publisherkits-socialpromoter' ) . '</p>';
			} else {
				$labels = array();
				$core   = PKCORE_Questions::core();
				foreach ( $gaps as $key ) {
					$labels[] = isset( $core[ $key ]['label'] ) ? $core[ $key ]['label'] : $key;
				}
				echo '<p>' . esc_html(
					sprintf(
						/* translators: %d: number of unanswered questions. */
						_n(
							'It also uses %d answer you have not given yet:',
							'It also uses %d answers you have not given yet:',
							count( $gaps ),
							'publisherkits-socialpromoter'
						),
						count( $gaps )
					)
				) . ' <em>' . esc_html( implode( '; ', $labels ) ) . '</em></p>';
				echo '<p><a class="button button-primary" href="' . esc_url( admin_url( 'admin.php?page=publisherkits-profile' ) ) . '">' . esc_html__( 'Review the Site Profile', 'publisherkits-socialpromoter' ) . '</a> ';
			}

			$dismiss = wp_nonce_url(
				add_query_arg(
					array(
						'action' => 'pkcore_dismiss_consumer',
						'handle' => rawurlencode( $handle ),
					),
					admin_url( 'admin-post.php' )
				),
				'pkcore_dismiss_' . $handle
			);
			echo '<a href="' . esc_url( $dismiss ) . '">' . esc_html__( 'Got it', 'publisherkits-socialpromoter' ) . '</a></p>';
			echo '</div>';
		}

		/**
		 * Mark a consumer announced.
		 *
		 * @return void
		 */
		public static function handle_dismiss() {
			if ( ! current_user_can( 'manage_options' ) ) {
				wp_die( esc_html__( 'You do not have permission to do that.', 'publisherkits-socialpromoter' ) );
			}
			$handle = isset( $_GET['handle'] ) ? sanitize_key( wp_unslash( $_GET['handle'] ) ) : '';
			check_admin_referer( 'pkcore_dismiss_' . $handle );

			$announced = get_option( self::OPTION, array() );
			$announced = is_array( $announced ) ? $announced : array();
			if ( '' !== $handle && ! in_array( $handle, $announced, true ) ) {
				$announced[] = $handle;
				update_option( self::OPTION, $announced, false );
			}

			wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url() );
			exit;
		}
	}
}
