<?php
/**
 * Location assigned Segments
 *
 * @link       https://personalizewp.com/
 * @since      3.2.0 Merged into PWP
 * @since      1.0.0
 *
 * @package    PersonalizeWP
 * @subpackage PersonalizeWP/Segments
 */

namespace PersonalizeWP\Segments;

use PersonalizeWP\Segments\Base;
use PersonalizeWP\Model\Activity;
use PersonalizeWP\Geo_Service;

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

/**
 * Location Segments
 *
 * Handles Activities with any type
 */
class Location extends Base {

	/**
	 * Types of Segment to process
	 *
	 * @var array
	 */
	protected $segment_types = array( 'location' );

	/**
	 * Add hooks. Overriden from parent to use catchall action.
	 */
	public function setup() {
		add_action( 'personalizewp_activity_record', array( $this, 'process_activity' ), 10, 2 );
	}

	/**
	 * Process any type of Activity for Segments.
	 *
	 * Overridden to have two args, required for catchall action.
	 *
	 * @param string   $type     Activity type
	 * @param Activity $activity Activity object
	 *
	 * @return void
	 */
	public function process_activity( $type, $activity = '' ) {

		if ( empty( $activity ) || empty( $activity->ip ) ) {
			return;
		}

		if ( ! isset( $this->segments ) ) {
			$this->segments = $this->get_segments();
		}

		if ( empty( $this->segments ) ) {
			return;
		}

		// Resolve full geo data from Activity IP address.
		$geo_result = Geo_Service::instance()->resolve( $activity->ip );
		if ( empty( $geo_result->country ) ) {
			// Nothing to match against.
			return;
		}

		foreach ( $this->segments as $segment ) {
			// Sanity check.
			if ( empty( $segment['conditions'] ) ) {
				continue;
			}

			$args = [
				'activity'    => $activity,
				'conditions'  => json_decode( $segment['conditions'], true ),
				'operator'    => $segment['operator'],
				'isocode'     => $geo_result->country,
				'subdivision' => $geo_result->subdivision,
			];
			if ( $this->activity_has_matched_conditions( $args ) ) {
				$this->assign_contact_to_segment( $segment['ID'], $activity->contact_id );
			}
		}
	}

	/**
	 * Test condition against Location criteria, matching international isocodes.
	 *
	 * Supports both country-only conditions and country+subdivision conditions.
	 *
	 * @since 2.3.0
	 * @since 3.5.0 Added subdivision support.
	 *
	 * @param array $args {
	 *     Array of args to use for matching the condition.
	 *
	 *     @type Activity $activity     Activity object - Unused
	 *     @type mixed    $condition    Country Code or condition array to match against
	 *     @type string   $isocode      Country isocode of Activity IP address
	 *     @type string   $subdivision  Subdivision code of Activity IP address
	 * }
	 *
	 * @return boolean
	 */
	protected function condition_has_matched_criteria( $args ) {

		list( 'condition' => $condition, 'isocode' => $isocode ) = $args;
		$subdivision = ! empty( $args['subdivision'] ) ? $args['subdivision'] : '';

		// Support for subdivision-level conditions (stored as arrays with country_code key).
		if ( is_array( $condition ) && ! empty( $condition['country_code'] ) ) {
			$subdivision_code = ! empty( $condition['subdivision'] ) ? $condition['subdivision'] : '';

			// Must match country first.
			if ( $isocode !== $condition['country_code'] ) {
				return false;
			}

			// Then match subdivision.
			return $subdivision === $subdivision_code;
		}

		// Standard country-only matching.
		return $isocode === $condition;
	}
}
