<?php
/**
 * Cleanup Job handler for ActionScheduler.
 *
 * @package EDD\Pro\CartRecovery\Jobs
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/GPL-3.0 GNU General Public License v3.0
 * @since 3.6.5
 */

namespace EDD\Pro\CartRecovery\Jobs;

use EDD\Pro\CartRecovery\Carts\Delete;

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

/**
 * Removes expired and abandoned carts and old email records.
 *
 * This cleanup job preserves carts with 'recovered' and 'converted' statuses
 * to maintain historical conversion data for accurate reporting. Only truly
 * abandoned or expired carts are removed based on the retention period.
 */
final class Cleanup {

	/**
	 * Job entry point: purge outdated records while preserving conversion data.
	 *
	 * @since 3.6.5
	 */
	public static function handle(): void {

		// Purge abandoned carts that have no products (empty carts from login events, etc.).
		$purged_empty = self::purge_empty_abandoned_carts();
		if ( $purged_empty > 0 ) {
			edd_debug_log( "[EDD ACR] Cleanup: deleted {$purged_empty} empty abandoned carts." );
		}

		$expired_before = time() - ( edd_get_option( 'acr_retention_days', 30 ) * DAY_IN_SECONDS );

		// Purge expired/abandoned carts (recovered carts are preserved for reporting).
		$delete       = new \EDD\Pro\CartRecovery\Carts\Delete();
		$purged_carts = $delete->delete_carts_before( $expired_before );
		edd_debug_log( "[EDD ACR] Cleanup: deleted {$purged_carts} expired/abandoned carts (preserved recovered/converted for reporting)." );

		// Purge orphaned email records older than the retention window.
		$purged_emails = $delete->delete_emails_before( $expired_before );
		edd_debug_log( "[EDD ACR] Cleanup: deleted {$purged_emails} orphaned email records." );
	}

	/**
	 * Deletes abandoned carts that have no products or cart total.
	 *
	 * These are carts that were incorrectly promoted to abandoned status despite
	 * having no actual cart contents. This cleans up any that slipped through.
	 *
	 * @since 3.6.5
	 * @return int Number of carts deleted.
	 */
	private static function purge_empty_abandoned_carts(): int {
		global $wpdb;

		$empty_cart_clause = Delete::get_empty_cart_where_clause();

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$deleted = $wpdb->query(
			"DELETE FROM {$wpdb->prefix}edd_acr_carts
			WHERE status = 'abandoned'
			  AND {$empty_cart_clause}"
		);

		return is_int( $deleted ) ? $deleted : 0;
	}
}
