<?php
/**
 * Condition: First purchase check.
 *
 * Evaluates whether the order appears to be the customer's first completed sale.
 *
 * @package EDD\Pro\Emails\ConditionalTags\Conditions
 * @copyright Copyright (c) 2026, Sandhills Development, LLC
 * @license https://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since 3.6.6
 */

namespace EDD\Pro\Emails\ConditionalTags\Conditions;

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

use EDD\Pro\Emails\ConditionalTags\Conditions\Traits\ParseData;

/**
 * Class FirstPurchase
 *
 * @since 3.6.6
 */
class FirstPurchase extends AbstractCondition {
	use ParseData;

	/**
	 * Supported contexts.
	 *
	 * @since 3.6.6
	 * @var string[]
	 */
	protected $supported_contexts = array( 'order' );

	/**
	 * Get the key for this condition.
	 *
	 * @since 3.6.6
	 *
	 * @return string Condition key.
	 */
	public function get_key() {
		return 'first_purchase';
	}

	/**
	 * Get the label for this condition.
	 *
	 * @since 3.6.6
	 *
	 * @return string Condition label.
	 */
	public function get_label() {
		return __( 'User\'s First Purchase', 'easy-digital-downloads' );
	}

	/**
	 * Evaluate whether this is the customer's first completed sale.
	 *
	 * @since 3.6.6
	 *
	 * @param int         $object_id  The EDD object ID.
	 * @param object      $edd_object The EDD object.
	 * @param object      $email      The EDD email object.
	 * @param mixed       $value      Optional expected boolean value.
	 * @param string|null $operator   Optional comparison operator.
	 * @param mixed       $context    Additional contextual data for evaluation.
	 * @return bool
	 */
	public function evaluate( $object_id, $edd_object, $email, $value, $operator = '=', $context = '' ) {
		if ( ! $this->is_context_allowed( $context ) ) {
			return false;
		}

		if ( ! $edd_object instanceof \EDD\Orders\Order || empty( $edd_object->customer_id ) ) {
			return false;
		}

		$current_order_id  = ! empty( $edd_object->id ) ? absint( $edd_object->id ) : absint( $object_id );
		$is_first_purchase = $this->is_first_purchase( absint( $edd_object->customer_id ), $current_order_id );

		// Boolean form: {if first_purchase}.
		if ( null === $operator && null === $value ) {
			return $is_first_purchase;
		}

		if ( ! in_array( $operator, array( '=', '!=' ), true ) ) {
			return false;
		}

		$expected = $this->parse_boolean( $value );
		if ( null === $expected ) {
			return false;
		}

		return '!=' === $operator ? $is_first_purchase !== $expected : $is_first_purchase === $expected;
	}

	/**
	 * Check if the current order is the customer's first completed sale.
	 *
	 * @since 3.6.6
	 *
	 * @param int $customer_id      The customer ID.
	 * @param int $current_order_id The current order ID to exclude.
	 * @return bool True when this resolves as the first completed sale.
	 */
	private function is_first_purchase( $customer_id, $current_order_id ) {
		$order_query_args = array(
			'type'        => 'sale',
			'status__in'  => edd_get_complete_order_statuses(),
			'customer_id' => absint( $customer_id ),
			'number'      => 1,
		);

		/*
		 * When no current order ID is available, query up to two completed
		 * orders to explicitly distinguish first purchase (exactly one)
		 * from repeat purchase (two or more).
		 */
		if ( empty( $current_order_id ) ) {
			$order_query_args['number'] = 2;

			return 1 === count( (array) edd_get_orders( $order_query_args ) );
		}

		$order_query_args['id__not_in'] = array( absint( $current_order_id ) );

		return empty( edd_get_orders( $order_query_args ) );
	}
}
