<?php
/**
 * Specific State/Region type condition Rules
 *
 * @link       https://personalizewp.com/
 * @since      3.5.0
 *
 * @package    PersonalizeWP
 * @subpackage PersonalizeWP/Rule_Conditions
 */

namespace PersonalizeWP\Rule_Conditions;

use PersonalizeWP\Geo_Service;

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

/**
 * Checks the current IP address of the user against known state/region conditions.
 *
 * Uses a country code stored in meta to first filter by country,
 * then compares the subdivision (state/province/region) code.
 */
class Visitor_State extends RuleCondition {

	public string $identifier = 'core_visitor_state';

	/**
	 * Measure key for the country code meta field.
	 *
	 * @var string
	 */
	public string $measure_key = 'country_code';

	/**
	 * Constructor
	 */
	public function __construct() {
		parent::__construct();

		$this->category = __( 'Core', 'personalizewp' );

		$this->description = __( 'User Location - State/Region', 'personalizewp' );

		$this->comparators = [
			'equals'         => _x( 'Is Equal To', 'Comparator', 'personalizewp' ),
			'does_not_equal' => _x( 'Does Not Equal', 'Comparator', 'personalizewp' ),
		];

		// Comparison values are loaded dynamically via AJAX based on selected country.
		$this->comparison_values = [];
	}

	/**
	 * Test data against condition.
	 *
	 * @param string $comparator Comparator to use.
	 * @param mixed  $value      Subdivision code to match against.
	 * @param string $action     Action context.
	 * @param mixed  $meta       Additional meta data containing country_code.
	 *
	 * @return bool
	 */
	public function matchesCriteria( $comparator, $value, $action, $meta = [] ): bool {
		$meta = (object) $meta;

		$expected_country = ! empty( $meta->country_code ) ? $meta->country_code : '';
		if ( empty( $expected_country ) ) {
			return false;
		}

		$geo_service = Geo_Service::instance();
		$result      = $geo_service->resolve();

		// Short-circuit: if visitor's country doesn't match the rule's country,
		// the rule is inapplicable — return false for both comparators.
		// A visitor from France is not "not in California"; the rule only
		// applies to visitors within the expected country.
		if ( empty( $result->country ) || $result->country !== $expected_country ) {
			return false;
		}

		switch ( $comparator ) {
			case 'equals':
				return $result->subdivision === $value;
			case 'does_not_equal':
				return $result->subdivision !== $value;
		}

		return false;
	}

	/**
	 * Convert to object for JSON serialization.
	 *
	 * Extends the base to include metadata about the cascading country/state UI.
	 *
	 * @return \stdClass
	 */
	public function toObject() {
		$base = parent::toObject();

		// Signal to JS that the meta field should be a country select dropdown.
		$base->metaFieldType = 'country_select';

		return $base;
	}
}
