<?php
/**
 * Review engine: asks for a WordPress.org review only when the plugin has
 * demonstrably worked for this shop — stock actually corrected from a stocktake,
 * over enough days of use. Shown only on the plugin's own screens, fully
 * dismissible (guideline 11 friendly).
 *
 * The test is always BEHAVIOUR, never a question. We do not ask "are you happy?"
 * and route the unhappy answer away from the review page: that is review gating,
 * it is what gets a listing pulled, and it is not what this does. Anyone can
 * review at any time; this only decides who is worth interrupting.
 *
 * @package Stocktake
 */

defined( 'ABSPATH' ) || exit;

/**
 * Class STWC_Review
 */
class STWC_Review {

	const OPTION     = 'stwc_review';
	const STAMP      = 'stwc_activated_at';
	const REVIEW_URL = 'https://wordpress.org/support/plugin/stocktake-for-woocommerce/reviews/#new-post';

	/**
	 * Wire hooks (admin only).
	 */
	public static function init() {
		add_action( 'admin_notices', array( __CLASS__, 'maybe_render' ) );
		add_action( 'admin_init', array( __CLASS__, 'handle_action' ) );
	}

	/**
	 * Current notice state.
	 *
	 * @return array{status:string,snooze_until:int}
	 */
	private static function state() {
		$state = get_option( self::OPTION, array() );
		return array(
			'status'       => isset( $state['status'] ) ? $state['status'] : 'pending',
			'snooze_until' => isset( $state['snooze_until'] ) ? (int) $state['snooze_until'] : 0,
		);
	}

	/**
	 * When this shop started using the plugin.
	 *
	 * New installs are stamped on activation. An install that predates this
	 * engine has no stamp, and starting its clock today would punish the shops
	 * that have used the plugin longest — so the first stocktake they ever
	 * created is used instead, and only a shop with no history at all starts
	 * from now.
	 *
	 * @return int Unix timestamp, 0 when unknown.
	 */
	public static function started_at() {
		$stamp = (int) get_option( self::STAMP, 0 );
		if ( $stamp > 0 ) {
			return $stamp;
		}

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-off backfill over the plugin's own table.
		$first = $wpdb->get_var( $wpdb->prepare( 'SELECT MIN(created_at) FROM %i', STWC_Sessions::sessions_table() ) );
		$stamp = $first ? (int) strtotime( (string) $first ) : time();

		update_option( self::STAMP, $stamp, false );

		return $stamp;
	}

	/**
	 * How many product lines this plugin has actually corrected on the shelf.
	 *
	 * The audit log records one 'applied' row per line written to live stock, so
	 * this is the plainest possible statement of value delivered: the number of
	 * stock figures the shop fixed with it.
	 *
	 * @return int
	 */
	public static function applied_lines() {
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- count over the plugin's own log table.
		return (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE event = %s', STWC_Log::table(), 'applied' ) );
	}

	/**
	 * Whether the ask should be shown right now.
	 *
	 * @return bool
	 */
	public static function should_show() {
		$state = self::state();
		if ( 'pending' !== $state['status'] ) {
			return false;
		}
		if ( $state['snooze_until'] > time() ) {
			return false;
		}

		$started = self::started_at();
		/**
		 * Filter the minimum days of use before asking for a review.
		 *
		 * @param int $days Default 7.
		 */
		$min_days = (int) apply_filters( 'stwc_review_min_days', 7 );
		if ( ! $started || ( time() - $started ) < $min_days * DAY_IN_SECONDS ) {
			return false;
		}

		/**
		 * Filter how many corrected stock lines count as "it worked for me".
		 *
		 * @param int $lines Default 10.
		 */
		return self::applied_lines() >= (int) apply_filters( 'stwc_review_min_applied', 10 );
	}

	/**
	 * Render the ask — only on the plugin's own screens.
	 */
	public static function maybe_render() {
		$screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
		if ( ! $screen || 'toplevel_page_' . STWC_Admin::SLUG !== $screen->id ) {
			return;
		}
		if ( ! current_user_can( STWC_Admin::CAP ) || ! self::should_show() ) {
			return;
		}

		$lines = self::applied_lines();
		$url   = static function ( $action ) {
			return wp_nonce_url( add_query_arg( 'stwc_review', $action ), 'stwc_review' );
		};
		// Deliberately NOT using the .notice class: several hosts and plugins hide
		// all .notice elements globally; a self-styled banner survives them.
		?>
		<div class="stwc-review-notice" style="display:flex;flex-wrap:wrap;align-items:center;gap:14px;padding:12px 16px;margin:12px 20px 8px 2px;background:#fff;border:1px solid #dcdcde;border-left:4px solid #2271b1;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.05);">
			<span style="font-size:26px;line-height:1;">📦</span>
			<div style="flex:1;">
				<p style="margin:0 0 2px;font-weight:600;">
					<?php
					printf(
						/* translators: %d: number of stock figures corrected from a stocktake */
						esc_html__( 'Stocktake has put %d stock figures right in your shop.', 'stocktake-for-woocommerce' ),
						(int) $lines
					);
					?>
				</p>
				<p style="margin:0;color:#50575e;">
					<?php esc_html_e( 'If it saves you time, a quick review on WordPress.org would help us a lot. Thank you!', 'stocktake-for-woocommerce' ); ?>
				</p>
			</div>
			<a class="button button-primary" target="_blank" rel="noopener" href="<?php echo esc_url( $url( 'done' ) ); ?>" onclick="window.open('<?php echo esc_url( self::REVIEW_URL ); ?>','_blank');">
				<?php esc_html_e( '⭐ Leave a review', 'stocktake-for-woocommerce' ); ?>
			</a>
			<a class="button" href="<?php echo esc_url( $url( 'later' ) ); ?>"><?php esc_html_e( 'Maybe later', 'stocktake-for-woocommerce' ); ?></a>
			<a href="<?php echo esc_url( $url( 'never' ) ); ?>" style="color:#757575;text-decoration:none;"><?php esc_html_e( 'Don’t ask again', 'stocktake-for-woocommerce' ); ?></a>
		</div>
		<?php
	}

	/**
	 * Persist the user's choice (done / later / never) and clean the URL.
	 */
	public static function handle_action() {
		if ( ! isset( $_GET['stwc_review'] ) || ! current_user_can( STWC_Admin::CAP ) ) {
			return;
		}
		check_admin_referer( 'stwc_review' );

		$action = sanitize_key( wp_unslash( $_GET['stwc_review'] ) );
		$state  = self::state();

		if ( 'done' === $action || 'never' === $action ) {
			$state['status'] = ( 'done' === $action ) ? 'done' : 'never';
		} elseif ( 'later' === $action ) {
			/**
			 * Filter the snooze duration in days for "maybe later".
			 *
			 * @param int $days Default 14.
			 */
			$state['snooze_until'] = time() + (int) apply_filters( 'stwc_review_snooze_days', 14 ) * DAY_IN_SECONDS;
		} else {
			return;
		}

		update_option( self::OPTION, $state, false );
		wp_safe_redirect( remove_query_arg( array( 'stwc_review', '_wpnonce' ) ) );
		exit;
	}
}
