<?php
/**
 * Recently Viewed Products Tracking
 *
 * Handles tracking of recently viewed products via cookies and JavaScript.
 *
 * @package GGM_Commerce
 */

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

/**
 * Class GGM_Commerce_Recently_Viewed
 *
 * Manages recently viewed products tracking.
 */
class GGM_Commerce_Recently_Viewed {

	/**
	 * Cookie name for storing recently viewed product IDs.
	 *
	 * @var string
	 */
	const COOKIE_NAME = 'ggmc_recently_viewed';

	/**
	 * Maximum number of products to track.
	 *
	 * @var int
	 */
	const MAX_PRODUCTS = 20;

	/**
	 * Cookie expiration in days.
	 *
	 * @var int
	 */
	const COOKIE_EXPIRATION_DAYS = 30;

	/**
	 * Singleton instance.
	 *
	 * @var GGM_Commerce_Recently_Viewed|null
	 */
	private static $instance = null;

	/**
	 * Get singleton instance.
	 *
	 * @return GGM_Commerce_Recently_Viewed
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		// Enqueue tracking script on frontend.
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
		// Output product ID in footer (after enqueued scripts have loaded).
		// Priority 99 ensures this runs AFTER wp_print_footer_scripts (priority 20).
		add_action( 'wp_footer', array( $this, 'output_product_tracking' ), 99 );
	}

	/**
	 * Enqueue tracking scripts.
	 */
	public function enqueue_scripts() {
		// Only enqueue if recently-viewed widget is activated.
		if ( ! class_exists( 'GGM_Commerce_License' ) || ! GGM_Commerce_License::instance()->is_widget_activated( 'recently-viewed' ) ) {
			return;
		}

		wp_enqueue_script(
			'ggmc-recently-viewed',
			plugins_url( 'assets/js/recently-viewed.js', dirname( __FILE__ ) ),
			array( 'jquery' ),
			'1.0.1',
			true
		);

		// Basic config without product ID (will be added in footer).
		wp_localize_script(
			'ggmc-recently-viewed',
			'ggmcRecentlyViewed',
			array(
				'cookieName'       => self::COOKIE_NAME,
				'maxProducts'      => self::MAX_PRODUCTS,
				'cookieExpiration' => self::COOKIE_EXPIRATION_DAYS,
				'currentProductId' => 0, // Will be set in footer.
				'cookiePath'       => COOKIEPATH,
			)
		);
	}

	/**
	 * Output product tracking script in footer.
	 * This runs after template_redirect so product ID is available.
	 */
	public function output_product_tracking() {
		// Only if recently-viewed is activated.
		if ( ! class_exists( 'GGM_Commerce_License' ) || ! GGM_Commerce_License::instance()->is_widget_activated( 'recently-viewed' ) ) {
			return;
		}

		// Get current product ID - should be set by now.
		$current_product_id = GGM_Commerce_Helpers::get_current_product_id();

		if ( $current_product_id && $current_product_id > 0 ) {
			?>
			<script>
			if (typeof ggmcRecentlyViewed !== 'undefined') {
				ggmcRecentlyViewed.currentProductId = <?php echo absint( $current_product_id ); ?>;
				// Trigger tracking immediately.
				if (typeof ggmcRecentlyViewedAPI !== 'undefined' && typeof ggmcRecentlyViewedAPI.trackCurrent === 'function') {
					ggmcRecentlyViewedAPI.trackCurrent();
				}
			}
			</script>
			<?php
		}
	}

	/**
	 * Get recently viewed product IDs from cookie.
	 *
	 * @param int $limit Maximum number of IDs to return.
	 * @return array Product IDs.
	 */
	public static function get_viewed_product_ids( $limit = 10 ) {
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON decoded and validated below
		$cookie_value = isset( $_COOKIE[ self::COOKIE_NAME ] ) ? wp_unslash( $_COOKIE[ self::COOKIE_NAME ] ) : '';

		if ( empty( $cookie_value ) ) {
			return array();
		}

		$ids = json_decode( $cookie_value, true );

		if ( ! is_array( $ids ) ) {
			return array();
		}

		// Sanitize and limit.
		$ids = array_map( 'absint', $ids );
		$ids = array_filter( $ids ); // Remove zeros.
		$ids = array_unique( $ids );

		return array_slice( $ids, 0, $limit );
	}

	/**
	 * Get recently viewed products.
	 *
	 * @param int  $limit           Maximum number of products to return.
	 * @param int  $exclude_current Whether to exclude current product.
	 * @return array Product objects.
	 */
	public static function get_viewed_products( $limit = 10, $exclude_current = true ) {
		$viewed_ids = self::get_viewed_product_ids( $limit + 1 ); // Get one extra in case we exclude current.

		if ( empty( $viewed_ids ) ) {
			return array();
		}

		// Optionally exclude current product.
		if ( $exclude_current ) {
			$current_id = GGM_Commerce_Helpers::get_current_product_id();
			if ( $current_id ) {
				$viewed_ids = array_diff( $viewed_ids, array( absint( $current_id ) ) );
			}
		}

		$viewed_ids = array_slice( $viewed_ids, 0, $limit );

		if ( empty( $viewed_ids ) ) {
			return array();
		}

		global $wpdb;
		$table_name  = $wpdb->prefix . 'ggmc_products';
		$ids_count   = count( $viewed_ids );
		$placeholder = implode( ',', array_fill( 0, $ids_count, '%d' ) );

		// Use FIELD() to maintain the order (most recently viewed first).
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table_name is safely constructed, placeholders are dynamic
		$query = $wpdb->prepare(
			"SELECT * FROM $table_name WHERE id IN ($placeholder) AND status = 'active' ORDER BY FIELD(id, $placeholder)",
			array_merge( $viewed_ids, $viewed_ids )
		);

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Query is prepared above
		return $wpdb->get_results( $query );
	}
}
