<?php
/**
 * Handles tracking and recording of analytics events.
 *
 * @package    Ai_Try_N_Buy
 * @subpackage Ai_Try_N_Buy/analytics
 * @author     Edu Brazeal <contact@edubrazeal.com>
 */
class Aitnb_Event_Tracker {

	/**
	 * The WordPress database access object.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      wpdb    $wpdb
	 */
	private $wpdb;

	/**
	 * The name of the custom analytics table.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @var      string    $table_name
	 */
	private $table_name;

	/**
	 * Constructor. Initializes the database object and table name.
	 *
	 * @since    1.0.0
	 */
	public function __construct() {
		global $wpdb;
		$this->wpdb       = $wpdb;
		$this->table_name = $this->wpdb->prefix . 'aitnb_analytics';
	}

	/**
	 * Registers the WordPress hooks for tracking events.
	 *
	 * @since    1.0.0
	 */
	public function register_hooks() {
		add_action( 'wp_ajax_aitnb_track_try_on_event', array( $this, 'ajax_track_try_on_event' ) );
		add_action( 'wp_ajax_nopriv_aitnb_track_try_on_event', array( $this, 'ajax_track_try_on_event' ) );

		add_action( 'woocommerce_payment_complete', array( $this, 'track_purchase_event' ) );
		add_action( 'woocommerce_order_status_processing', array( $this, 'track_purchase_event' ) );
		add_action( 'woocommerce_order_status_completed', array( $this, 'track_purchase_event' ) );
	}

	/**
	 * Handles the AJAX request to track a 'try' event.
	 *
	 * @since    1.0.0
	 */
	public function ajax_track_try_on_event() {
		if ( ! check_ajax_referer( 'aitnb_public_nonce', 'nonce', false ) ) {
			wp_send_json_error( array( 'message' => 'Security check failed.' ) );
			return;
		}

		if ( ! isset( $_POST['product_id'] ) ) {
			wp_send_json_error( array( 'message' => 'Product ID not provided.' ) );
			return;
		}

		$product_id = absint( $_POST['product_id'] );

		if ( 'product' !== get_post_type( $product_id ) ) {
			wp_send_json_error( array( 'message' => 'Invalid product.' ) );
			return;
		}

		$result = $this->record_event( $product_id, 'try' );

		if ( $result ) {
			wp_send_json_success(
				array(
					'message'    => 'Event tracked successfully.',
					'session_id' => $this->get_session_id(),
				)
			);
		} else {
			wp_send_json_error( array( 'message' => 'Failed to record event.' ) );
		}
	}

	/**
	 * Tracks a purchase event when an order reaches a completed status.
	 *
	 * @since    1.0.0
	 * @param    int    $order_id    The ID of the order.
	 */
	public function track_purchase_event( $order_id ) {
		$already_tracked = get_post_meta( $order_id, '_aitnb_purchase_tracked', true );
		if ( $already_tracked ) {
			return;
		}

		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			return;
		}

		$user_id = $order->get_user_id();
		$items   = $order->get_items();

		foreach ( $items as $item ) {
			$product_id = $item->get_product_id();

			if ( 'yes' === get_post_meta( $product_id, '_aitnb_enable_tryon', true ) ) {
				$session_id      = $this->get_session_id();
				$has_try_event = $this->check_try_event_exists( $product_id, $session_id );

				if ( $has_try_event ) {
					$this->record_event( $product_id, 'purchase', $user_id );
				}
			}
		}

		update_post_meta( $order_id, '_aitnb_purchase_tracked', current_time( 'mysql' ) );
	}

	/**
	 * Checks if a try event exists for a product and session.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @param    int       $product_id    The product ID.
	 * @param    string    $session_id    The session ID.
	 * @return   bool                     True if try event exists, false otherwise.
	 */
	private function check_try_event_exists( $product_id, $session_id ) {
		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$query = $this->wpdb->prepare(
			"SELECT COUNT(id) FROM {$this->table_name}
			WHERE product_id = %d
			AND session_id = %s
			AND event_type = %s
			LIMIT 1",
			$product_id,
			$session_id,
			'try'
		);

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
		$count = $this->wpdb->get_var( $query );

		return (int) $count > 0;
	}

	/**
	 * Inserts an event record into the custom database table.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @param    int       $product_id    The product ID.
	 * @param    string    $event_type    The event type ('try' or 'purchase').
	 * @param    int|null  $user_id       The user ID if available.
	 * @return   bool                     True on success, false on failure.
	 */
	private function record_event( $product_id, $event_type, $user_id = null ) {
		if ( null === $user_id ) {
			$user_id = get_current_user_id();
		}

		$session_id = $this->get_session_id();

		$result = $this->wpdb->insert(
			$this->table_name,
			array(
				'product_id'      => $product_id,
				'user_id'         => $user_id,
				'session_id'      => $session_id,
				'event_type'      => $event_type,
				'event_timestamp' => current_time( 'mysql', 1 ),
			),
			array(
				'%d',
				'%d',
				'%s',
				'%s',
				'%s',
			)
		);

		if ( false === $result ) {
			return false;
		}

		return true;
	}

	/**
	 * Gets a unique session ID for tracking guest users.
	 *
	 * @since    1.0.0
	 * @access   private
	 * @return   string    A unique session identifier.
	 */
	private function get_session_id() {
		$cookie_name = 'aitnb_session_id';
		
		if ( isset( $_COOKIE[ $cookie_name ] ) ) {
			return sanitize_text_field( wp_unslash( $_COOKIE[ $cookie_name ] ) );
		}

		$session_id = wp_generate_uuid4();
		
		if ( ! headers_sent() ) {
			$expire = time() + ( 86400 * 30 );
			
			if ( version_compare( PHP_VERSION, '7.3.0', '>=' ) ) {
				setcookie(
					$cookie_name,
					$session_id,
					array(
						'expires'  => $expire,
						'path'     => COOKIEPATH ? COOKIEPATH : '/',
						'domain'   => COOKIE_DOMAIN ? COOKIE_DOMAIN : '',
						'secure'   => is_ssl(),
						'httponly' => false,
						'samesite' => 'Lax',
					)
				);
			} else {
				setcookie(
					$cookie_name,
					$session_id,
					$expire,
					COOKIEPATH ? COOKIEPATH : '/',
					COOKIE_DOMAIN ? COOKIE_DOMAIN : '',
					is_ssl(),
					false
				);
			}
		}

		return $session_id;
	}

	/**
	 * Gets statistics about tracked events (useful for debugging).
	 *
	 * @since    1.0.0
	 * @return   array    Statistics about tracked events.
	 */
	public function get_tracking_stats() {
		$stats = array();

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$try_query = $this->wpdb->prepare(
			"SELECT COUNT(id) FROM {$this->table_name} WHERE event_type = %s",
			'try'
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
		$stats['try_count'] = $this->wpdb->get_var( $try_query );

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$purchase_query = $this->wpdb->prepare(
			"SELECT COUNT(id) FROM {$this->table_name} WHERE event_type = %s",
			'purchase'
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
		$stats['purchase_count'] = $this->wpdb->get_var( $purchase_query );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$stats['unique_sessions'] = $this->wpdb->get_var(
			"SELECT COUNT(DISTINCT session_id) FROM {$this->table_name}"
		);

		return $stats;
	}
}