<?php
/**
 * CartAbandonedTrigger — detects abandoned carts.
 *
 * v1.3: DeferredStateCheck cancels play if cart purchased before delay fires.
 *       Queue cancellation via cart status check.
 *
 * @package CartCue
 */

namespace CartCue\Triggers;

use CartCue\DB;

defined( 'ABSPATH' ) || exit;

class CartAbandonedTrigger extends AbstractTrigger {

	public function get_slug(): string {
		return 'cart_abandoned';
	}

	public function get_label(): string {
		return __( 'Cart Abandoned', 'cartcue-sales-automation' );
	}

	public function get_sentence(): string {
		return __( 'someone leaves items in their cart', 'cartcue-sales-automation' );
	}

	public function get_description(): string {
		return __( 'Someone leaves items in their cart.', 'cartcue-sales-automation' );
	}

	public function supports_recheck(): bool {
		return true;
	}

	/**
	 * DeferredStateCheck: skip the play if the cart was already purchased.
	 * This prevents sending "you left something behind" after a customer bought.
	 */
	public function is_still_valid( array $data ): bool {
		global $wpdb;
		$cart_id = (int) ( $data['cart_id'] ?? 0 );
		if ( ! $cart_id ) {
			return false;
		}
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$status = $wpdb->get_var( $wpdb->prepare(
			'SELECT status FROM %i WHERE id = %d',
			DB::carts(),
			$cart_id
		) );
		// Only valid if cart is still in 'triggered' state (not purchased).
		return in_array( $status, [ 'active', 'triggered' ], true );
	}

	public function get_settings_fields(): array {
		return [
			[
				'key'     => 'abandonment_minutes',
				'label'   => __( 'Wait this many minutes before cart is abandoned', 'cartcue-sales-automation' ),
				'type'    => 'number',
				'default' => 15,
			],
			[
				'key'     => 'registered_only',
				'label'   => __( 'Who should this include?', 'cartcue-sales-automation' ),
				'type'    => 'select',
				'default' => 'no',
				'options' => [
					'no'  => __( 'All customers (registered + guests)', 'cartcue-sales-automation' ),
					'yes' => __( 'Registered customers only', 'cartcue-sales-automation' ),
				],
			],
		];
	}

	public function get_test_data(): array {
		return [
			'trigger'        => $this->get_slug(),
			'cart_id'        => 0,
			'customer_id'    => 0,
			'customer_email' => get_option( 'admin_email', '' ),
			'cart_total'     => wc_price( 99.00 ),
			'_is_test'       => true,
		];
	}

	public function register_hooks(): void {
		add_action( 'woocommerce_cart_updated',                       [ $this, 'save_cart' ] );
		add_action( 'wp_ajax_nopriv_cartcue_capture_email',         [ $this, 'ajax_capture_email' ] );
		add_action( 'wp_ajax_cartcue_capture_email',                [ $this, 'ajax_capture_email' ] );
		add_action( 'wp_enqueue_scripts',                             [ $this, 'enqueue_checkout_script' ] );
		add_action( 'woocommerce_checkout_order_created',             [ $this, 'mark_cart_purchased' ] );
		add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'mark_cart_purchased' ] );
	}

	// -------------------------------------------------------------------------
	// Cart tracking
	// -------------------------------------------------------------------------

	public function save_cart(): void {
		if ( ! WC()->cart || WC()->cart->is_empty() ) {
			return;
		}

		$session     = WC()->session;
		$session_key = $session ? (string) $session->get_customer_id() : '';
		if ( $session_key ) {
			$lock = 'cartcue_cart_save_' . md5( $session_key );
			if ( get_transient( $lock ) ) {
				return;
			}
			set_transient( $lock, 1, 5 );
		}

		$user_id = get_current_user_id();
		$email   = '';

		if ( $user_id ) {
			$user  = get_user_by( 'id', $user_id );
			$email = $user ? $user->user_email : '';
		}

		$cart_data = [];
		foreach ( WC()->cart->get_cart() as $key => $item ) {
			$cart_data[ $key ] = [
				'product_id'   => (int) ( $item['product_id']   ?? 0 ),
				'variation_id' => (int) ( $item['variation_id'] ?? 0 ),
				'quantity'     => (int) ( $item['quantity']     ?? 1 ),
			];
		}

		$contents_json = wp_json_encode( $cart_data );
		$cart_hash     = md5( (string) $contents_json );
		if ( $session_key ) {
			$hash_key = 'cartcue_cart_hash_' . md5( $session_key );
			if ( get_transient( $hash_key ) === $cart_hash ) {
				return;
			}
			set_transient( $hash_key, $cart_hash, 5 );
		}

		$this->upsert_cart( [
			'user_id'       => $user_id,
			'email'         => $email,
			'session_token' => $session_key,
			'cart_contents' => $contents_json,
			'total'         => sanitize_text_field( wp_strip_all_tags( WC()->cart->get_cart_total() ) ),
			'status'        => 'active',
			'updated_at'    => current_time( 'mysql' ),
		] );
	}

	private function upsert_cart( array $data ): void {
		global $wpdb;

		$existing_id = null;
		if ( $data['user_id'] ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$existing_id = $wpdb->get_var( $wpdb->prepare(
				"SELECT id FROM %i WHERE user_id = %d AND status = 'active' LIMIT 1",
				DB::carts(),
				$data['user_id']
			) );
		} elseif ( $data['session_token'] ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$existing_id = $wpdb->get_var( $wpdb->prepare(
				"SELECT id FROM %i WHERE session_token = %s AND status = 'active' LIMIT 1",
				DB::carts(),
				$data['session_token']
			) );
		}

		if ( $existing_id ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->update( DB::carts(), [
				'cart_contents' => $data['cart_contents'],
				'total'         => $data['total'],
				'updated_at'    => $data['updated_at'],
				'email'         => $data['email'],
			], [ 'id' => $existing_id ], [ '%s', '%s', '%s', '%s' ], [ '%d' ] );
		} else {
			$data['created_at']             = current_time( 'mysql' );
			$data['checkout_started_at']    = null;
			$data['checkout_started_fired'] = 0;
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->insert( DB::carts(), $data );
		}
	}

	// -------------------------------------------------------------------------
	// Guest email capture
	// -------------------------------------------------------------------------

	public function enqueue_checkout_script(): void {
		if ( ! is_checkout() ) { return; }
		wp_enqueue_script( 'cartcue-checkout', CARTCUE_PLUGIN_URL . 'assets/js/checkout.js', [ 'jquery' ], CARTCUE_VERSION, true );
		wp_localize_script( 'cartcue-checkout', 'cartcueCheckout', [
			'ajaxUrl' => admin_url( 'admin-ajax.php' ),
			'nonce'   => wp_create_nonce( 'cartcue_capture_email' ),
		] );
	}

	public function ajax_capture_email(): void {
		check_ajax_referer( 'cartcue_capture_email', 'nonce' );
		$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) );
		if ( ! is_email( $email ) ) {
			wp_send_json_error( 'invalid_email' );
		}

		$ip_key = 'cartcue_capture_rl_' . md5( sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ?? 'unknown' ) ) );
		if ( ! RateLimiter::allow( $ip_key, 30, MINUTE_IN_SECONDS ) ) {
			wp_send_json_error( 'rate_limited', 429 );
		}

		$session     = WC()->session;
		$session_key = $session ? $session->get_customer_id() : '';
		if ( ! $session_key ) {
			wp_send_json_error( 'no_session' );
		}

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$wpdb->query(
			$wpdb->prepare(
				"UPDATE %i SET email = %s WHERE session_token = %s AND status IN ('active','checkout_started')",
				DB::carts(),
				$email,
				$session_key
			)
		);
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$cart_id = (int) $wpdb->get_var(
			$wpdb->prepare(
				"SELECT id FROM %i WHERE session_token = %s ORDER BY id DESC LIMIT 1",
				DB::carts(),
				$session_key
			)
		);
		if ( $cart_id && is_checkout() ) {
			CheckoutStartedTrigger::mark_checkout_started( $cart_id );
		}
		wp_send_json_success();
	}

	// -------------------------------------------------------------------------
	// Mark purchased — cancels any queued plays for this customer
	// -------------------------------------------------------------------------

	public function mark_cart_purchased( $order ): void {
		if ( ! $order instanceof \WC_Order ) { return; }

		global $wpdb;
		$user_id = $order->get_customer_id();
		$email   = $order->get_billing_email();

		// Mark cart as purchased — is_still_valid() will see this and cancel queued plays.
		if ( $user_id ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->query( $wpdb->prepare(
				"UPDATE %i SET status = 'purchased' WHERE user_id = %d AND status IN ('active','triggered')",
				DB::carts(),
				$user_id
			) );
		} elseif ( $email ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->query( $wpdb->prepare(
				"UPDATE %i SET status = 'purchased' WHERE email = %s AND status IN ('active','triggered')",
				DB::carts(),
				$email
			) );
		}
	}

	// -------------------------------------------------------------------------
	// Scheduled abandonment processing
	// -------------------------------------------------------------------------

	public function process_abandoned_carts(): void {
		global $wpdb;

		$workflows = $this->plugin->runner->get_active_workflows_for_trigger( $this->get_slug() );
		if ( empty( $workflows ) ) { return; }

		$min_minutes = 15;
		foreach ( $workflows as $wf ) {
			$minutes     = (int) ( $wf['trigger_settings']['abandonment_minutes'] ?? 15 );
			$min_minutes = min( $min_minutes, max( 5, $minutes ) );
		}

		$cutoff = gmdate( 'Y-m-d H:i:s', time() - ( $min_minutes * MINUTE_IN_SECONDS ) );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$carts = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM %i
				 WHERE status = 'active' AND updated_at <= %s AND email != ''
				 ORDER BY updated_at ASC LIMIT 200",
				DB::carts(),
				$cutoff
			),
			ARRAY_A
		) ?: [];

		foreach ( $carts as $cart ) {
			foreach ( $workflows as $wf ) {
				$registered_only = $wf['trigger_settings']['registered_only'] ?? 'no';
				if ( 'yes' === $registered_only && empty( $cart['user_id'] ) ) { continue; }

				$wf_minutes = (int) ( $wf['trigger_settings']['abandonment_minutes'] ?? 15 );
				$wf_cutoff  = gmdate( 'Y-m-d H:i:s', time() - ( $wf_minutes * MINUTE_IN_SECONDS ) );
				if ( $cart['updated_at'] > $wf_cutoff ) { continue; }

				$this->plugin->runner->trigger( (int) $wf['id'], [
					'trigger'        => $this->get_slug(),
					'cart_id'        => (int) $cart['id'],
					'customer_id'    => (int) $cart['user_id'],
					'customer_email' => $cart['email'],
					'cart_total'     => $cart['total'],
				] );
			}

			// phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->update( DB::carts(), [ 'status' => 'triggered' ], [ 'id' => $cart['id'] ], [ '%s' ], [ '%d' ] );
		}
	}

	/**
	 * Delete stale active cart rows that were never abandoned (session expired, etc.).
	 */
	public function prune_stale_carts(): void {
		global $wpdb;

		$active_days = max( 7, (int) apply_filters( 'cartcue_cart_prune_days', 30 ) );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM %i WHERE status = 'active' AND updated_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
				DB::carts(),
				$active_days
			)
		);

		$terminal_days = max( 30, (int) apply_filters( 'cartcue_cart_retention_days', 90 ) );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM %i
				 WHERE status IN ('triggered','purchased','checkout_started')
				   AND updated_at < DATE_SUB(NOW(), INTERVAL %d DAY)",
				DB::carts(),
				$terminal_days
			)
		);
	}
}
