<?php
/**
 * Cart Event Subscriber for Cart Recovery
 *
 * Handles WordPress events related to cart modifications and loading.
 *
 * @package EDD\Pro\CartRecovery\Events
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/GPL-2.0 GNU Public License
 * @since   3.6.5
 */

declare(strict_types=1);

namespace EDD\Pro\CartRecovery\Events;

use EDD\EventManagement\SubscriberInterface;
use EDD\Pro\CartRecovery\Snapshots\SnapshotPersistence;
use EDD\Pro\CartRecovery\Journey\EventLogger;
use EDD\Pro\CartRecovery\Traits\Debug;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;

/**
 * Cart Event Subscriber class.
 *
 * Subscribes to WordPress events related to cart changes and persists snapshots.
 */
class CartEventSubscriber implements SubscriberInterface {
	use Debug;

	/**
	 * Snapshot persistence instance.
	 *
	 * @var SnapshotPersistence
	 */
	private SnapshotPersistence $snapshot_persistence;

	/**
	 * Event logger instance.
	 *
	 * @var EventLogger
	 */
	private EventLogger $event_logger;

	/**
	 * Constructor.
	 *
	 * @since 3.6.5
	 * @param SnapshotPersistence $snapshot_persistence Snapshot persistence instance.
	 * @param EventLogger|null    $event_logger         Event logger instance.
	 */
	public function __construct( SnapshotPersistence $snapshot_persistence, ?EventLogger $event_logger = null ) {
		$this->snapshot_persistence = $snapshot_persistence;
		$this->event_logger         = $event_logger ?? new EventLogger();
	}

	/**
	 * Returns subscribed events.
	 *
	 * @since 3.6.5
	 * @return array Event subscriptions.
	 */
	public static function get_subscribed_events(): array {
		return array(
			'edd_post_add_to_cart'             => array( 'on_cart_changed', 20 ),
			'edd_post_remove_from_cart'        => array( 'on_cart_changed', 20 ),
			'edd_cart_discounts_updated'       => array( 'on_cart_changed', 20 ),
			'edd_cart_discounts_removed'       => array( 'on_cart_changed', 20 ),
			'edd_after_set_cart_item_quantity' => array( 'on_cart_changed', 20 ),
			'edd_cart_tax_recalculated'        => array( 'on_cart_changed', 20 ),
			'edd_empty_cart'                   => array( 'on_cart_emptied', 20 ),
		);
	}

	/**
	 * Handles cart mutations by persisting a fresh snapshot.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	public function on_cart_changed(): void {
		$result = $this->snapshot_persistence->persist_snapshot();

		$this->log( sprintf( 'Cart changed - persist_snapshot result: %s', wp_json_encode( $result ) ) );

		// Log journey event if cart was persisted.
		if ( is_array( $result ) && ! empty( $result['cart_id'] ) ) {
			$cart_id = (int) $result['cart_id'];

			// Check if this is a new cart by looking for existing cart_created event.
			$query           = new \EDD\Pro\CartRecovery\Database\Queries\JourneyEvent();
			$existing_events = $query->query(
				array(
					'cart_id'    => $cart_id,
					'event_type' => 'cart_created',
					'number'     => 1,
				)
			);

			$is_new_cart = empty( $existing_events );

			// Log cart_created for new carts, cart_updated for existing.
			$event_type = $is_new_cart ? 'cart_created' : 'cart_updated';
			$event_data = array(
				'cart_total' => edd_get_cart_total(),
				'item_count' => edd_get_cart_quantity(),
			);

			$this->log( sprintf( 'Logging %s event for cart %d', $event_type, $cart_id ) );

			$event_id = $this->event_logger->log_cart_event( $event_type, $cart_id, $event_data );

			if ( $event_id ) {
				$this->log( sprintf( 'Successfully logged %s event (ID: %d) for cart %d', $event_type, $event_id, $cart_id ) );
			} else {
				$this->log( sprintf( 'Failed to log %s event for cart %d', $event_type, $cart_id ), true );
			}
		} else {
			$this->log( 'Cart snapshot not persisted or no cart_id returned' );
		}
	}

	/**
	 * Handles explicit cart empty events.
	 *
	 * When a cart is emptied, this deletes the stored recovery cart.
	 * Skips deletion during purchase completion - the CheckoutEventSubscriber
	 * handles marking carts as recovered in that case.
	 *
	 * @since 3.6.5
	 * @return void
	 */
	public function on_cart_emptied(): void {
		// Ignore cart emptied events during purchase completion.
		if ( did_action( 'edd_complete_purchase' ) ) {
			return;
		}

		$this->snapshot_persistence->persist_snapshot();
	}
}
