<?php
/**
 * Query 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;

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

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

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

	/**
	 * 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->url ) ) {
			return;
		}

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

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

		// Clean Up URL, retaining only query and fragment parameters. URL is lower cased first for later ease.
		$activity_url = strtolower( $activity->url );
		$queries      = wp_parse_url( $activity_url, PHP_URL_QUERY );
		$fragments    = wp_parse_url( $activity_url, PHP_URL_FRAGMENT );
		// Check for something to do.
		if ( empty( $queries ) && empty( $fragments ) ) {
			return;
		}

		$query_params    = [];
		$fragment_params = [];
		// Parse query and possible fragment args into arrays for easier processing.
		if ( ! empty( $queries ) ) {
			parse_str( $queries, $query_params );
		}
		if ( ! empty( $fragments ) ) {
			parse_str( $fragments, $fragment_params );
		}

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

			$args = [
				'activity'        => $activity,
				'conditions'      => json_decode( strtolower( $segment['conditions'] ), true ),
				'operator'        => $segment['operator'],
				'query_params'    => $query_params,
				'fragment_params' => $fragment_params,
			];
			if ( $this->activity_has_matched_conditions( $args ) ) {
				$this->assign_contact_to_segment( $segment['ID'], $activity->contact_id );
			}
		}
	}

	/**
	 * Test condition against query/fragment URL criteria.
	 *
	 * @since 2.3.0
	 *
	 * @param array $args {
	 *     Array of args to use for matching the condition.
	 *
	 *     @type Activity $activity         Activity object - Unused
	 *     @type mixed    $condition        Query/fragment key to match
	 *     @type mixed    $options          Possible key values to match
	 *     @type array    $query_params     URL query params
	 *     @type array    $fragment_params  URL fragment params
	 * }
	 *
	 * @return boolean
	 */
	protected function condition_has_matched_criteria( $args ) {

		list( 'condition' => $query_key, 'options' => $query_values, 'query_params' => $query_params, 'fragment_params' => $fragment_params ) = $args;

		// Search for query key and optional values
		$matching_search_key  = array_key_exists( $query_key, $query_params ) && empty( $query_values );
		$match_search_key_val = array_key_exists( $query_key, $query_params ) && ! empty( $query_values ) && in_array( $query_params[ $query_key ], $query_values, true );
		// Duplicate search within possible Fragment args
		$matching_fragment_key  = array_key_exists( $query_key, $fragment_params ) && empty( $query_values );
		$match_fragment_key_val = array_key_exists( $query_key, $fragment_params ) && ! empty( $query_values ) && in_array( $fragment_params[ $query_key ], $query_values, true );

		if ( $matching_search_key || $match_search_key_val || $matching_fragment_key || $match_fragment_key_val ) {
			return true;
		}

		return false;
	}
}
