<?php
/**
 * Preview Data Helper for ACR Emails.
 *
 * @package     EDD\Pro\CartRecovery\Emails
 * @copyright   Copyright (c) 2026, Sandhills Development, LLC
 * @license     https://opensource.org/licenses/GPL-2.0 GNU Public License
 * @since       3.6.5
 */

namespace EDD\Pro\CartRecovery\Emails\Templates\Traits;

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

/**
 * Helper class to generate preview data for abandoned cart recovery emails.
 *
 * @since 3.6.5
 */
trait PreviewData {

	/**
	 * Cached cart object.
	 *
	 * @var object|null
	 */
	private static $cart = null;

	/**
	 * Gets a cart object for preview purposes.
	 *
	 * Either retrieves a real abandoned cart from the database or generates a mock cart.
	 *
	 * @since 3.6.5
	 * @return object
	 */
	public static function get_cart(): object {
		if ( ! is_null( self::$cart ) ) {
			return self::$cart;
		}

		// Try to get a real abandoned cart from the database.
		$cart = self::get_abandoned_cart_from_db();

		// If no real cart exists, create a mock cart.
		if ( ! $cart ) {
			$cart = self::create_mock_cart();
		}

		self::$cart = $cart;

		return self::$cart;
	}

	/**
	 * Gets preview data as constructor arguments for ACR email types.
	 *
	 * Returns an array that can be spread into the AbstractRecoveryEmail constructor.
	 *
	 * @since 3.6.5
	 * @return array Array containing [cart_object, token_data_array]
	 */
	protected function get_preview_data(): array {
		$cart       = self::get_cart();
		$token_data = self::get_token_data( $cart );

		return array( $cart, $token_data );
	}

	/**
	 * Attempts to retrieve a real abandoned cart from the database.
	 *
	 * @since 3.6.5
	 * @return object|null
	 */
	private static function get_abandoned_cart_from_db() {
		try {

			// Query for abandoned carts with email addresses.
			$query = new \EDD\Pro\CartRecovery\Database\Queries\RecoveryCart(
				array(
					'status__in' => array( 'abandoned', 'abandoned_ir', 'abandoned_vr', 'abandoned_fa' ),
					'number'     => 10,
				)
			);
			$carts = $query->query();

			if ( ! empty( $carts ) ) {
				// Return a random cart from the results.
				return $carts[ array_rand( $carts ) ];
			}
		} catch ( \Exception $e ) {
			// Silently fail and fall back to mock data.
			edd_debug_log( 'ACR Preview: Failed to fetch cart from database: ' . $e->getMessage() );
		}

		return null;
	}

	/**
	 * Creates a mock cart object for preview purposes.
	 *
	 * @since 3.6.5
	 * @return object
	 */
	private static function create_mock_cart(): object {
		$sample_products = self::get_sample_products();

		// Build cart contents JSON.
		$cart_items = array(
			'items' => array(),
		);

		$total = 0;

	foreach ( $sample_products as $product ) {
		$cart_items['items'][] = array(
			'id'       => $product['id'],
			'name'     => $product['name'],
			'price_id' => null,
			'quantity' => 1,
			'price'    => $product['price'],
			'options'  => array(),
		);
		$total                += $product['price'];
	}

		return (object) array(
			'id'                   => 0,
			'session_id'           => 'preview_session',
			'customer_id'          => null,
			'email'                => 'customer@example.com',
			'cart_contents'        => wp_json_encode( $cart_items ),
			'cart_total'           => $total,
			'currency'             => edd_get_currency(),
			'discount_applied'     => null,
			'browser_fingerprint'  => null,
			'timezone'             => null,
			'date_expired'         => gmdate( 'Y-m-d H:i:s', strtotime( '+7 days' ) ),
			'cart_version'         => 1,
			'status'               => 'abandoned',
			'date_abandoned'       => gmdate( 'Y-m-d H:i:s', strtotime( '-1 hour' ) ),
			'date_recovered'       => null,
			'order_id'             => null,
			'recovery_email_count' => 0,
			'last_recovery_email'  => null,
			'user_agent'           => 'Mozilla/5.0',
			'ip_address'           => '127.0.0.1',
			'referrer_url'         => null,
			'fail_count'           => 0,
			'date_unsubscribed'    => null,
			'date_created'         => gmdate( 'Y-m-d H:i:s', strtotime( '-2 hours' ) ),
			'date_modified'        => gmdate( 'Y-m-d H:i:s', strtotime( '-1 hour' ) ),
		);
	}

	/**
	 * Gets sample products for the mock cart.
	 *
	 * @since 3.6.5
	 * @return array
	 */
	private static function get_sample_products(): array {
		// Try to get real products from the database.
		$downloads = get_posts(
			array(
				'post_type'   => 'download',
				'numberposts' => 2,
				'post_status' => 'publish',
			)
		);

		$products = array();

		if ( ! empty( $downloads ) ) {
			foreach ( $downloads as $download ) {
				$download_object = edd_get_download( $download->ID );

				$products[] = array(
					'id'    => $download->ID,
					'name'  => $download->post_title,
					'price' => $download_object->get_price(),
				);
			}
		}

		// If no real products exist, use mock data.
		if ( empty( $products ) ) {
			$products = array(
				array(
					'id'    => 1,
					'name'  => __( 'Sample Product 1', 'easy-digital-downloads' ),
					'price' => 49.00,
				),
				array(
					'id'    => 2,
					'name'  => __( 'Sample Product 2', 'easy-digital-downloads' ),
					'price' => 50.00,
				),
			);
		}

		return $products;
	}

	/**
	 * Generates mock token data for preview purposes.
	 *
	 * @since 3.6.5
	 * @param object $cart The cart object.
	 * @return array
	 */
	private static function get_token_data( object $cart ): array {
		return array(
			'token'      => 'preview_token_' . md5( 'preview' . time() ),
			'expires_at' => time() + ( DAY_IN_SECONDS * 7 ),
			'cart_id'    => isset( $cart->id ) ? $cart->id : 0,
		);
	}
}
