<?php

namespace wpbuddy\rich_snippets\pro;

use wpbuddy\rich_snippets\Position_Rule;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
} // Exit if accessed directly


/**
 * Class Rules.
 *
 * Functions to read and write Rulesets.
 *
 * @package wpbuddy\rich_snippets
 *
 * @since   2.0.0
 */
class Rules_Model extends \wpbuddy\rich_snippets\Rules_Model {

	/**
	 * Initializes all the match rules for the PRO version.
	 *
	 * @since 2.19.18
	 */
	public static function init_filters() {

		add_filter( 'wpbuddy/rich_snippets/rule/match_post_template', [
			__CLASS__,
			'match_post_template'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_post_template', [
			__CLASS__,
			'match_post_template'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_post_format', [
			__CLASS__,
			'match_post_format'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_child_terms', [
			__CLASS__,
			'match_child_terms'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_post_taxonomy', [
			__CLASS__,
			'match_post_taxonomy'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_page_template', [
			__CLASS__,
			'match_page_template'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_page_type', [
			__CLASS__,
			'match_page_type'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_page_parent', [
			__CLASS__,
			'match_page_parent'
		], 10, 2 );

		add_filter( 'wpbuddy/rich_snippets/rule/match_user', [
			__CLASS__,
			'match_user'
		], 10, 2 );
	}


	/**
	 * Checks if the current post matches a specific template.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 * @param string $post_type
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_post_template( $ret, $rule, string $post_type = '' ): bool {

		$query = $rule->get_query();

		if ( empty( $post_type ) ) {
			# extract the post type
			$post_type = strstr( $rule->value, ':', true );
		}

		if ( ! $query->is_singular( $post_type ) ) {
			return false;
		}

		$file = get_page_template_slug( $query->post->ID );

		# if the default template is in use, get_page_template_slug() will return an empty string
		if ( empty( $file ) ) {
			$file = 'default';
		}

		return $rule->compare(
			sprintf(
				'%s%s%s',
				$post_type,
				! empty( $post_type ) ? ':' : '',
				$file
			)
		);
	}


	/**
	 * Checks if the current post has a special post status.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_post_status( $ret, $rule ): bool {

		$query = $rule->get_query();

		if ( ! $query->is_singular() ) {
			return false;
		}

		$current_post = $query->post;

		if ( ! is_a( $current_post, '\WP_Post' ) ) {
			return false;
		}

		return $rule->compare( get_post_status( $current_post ) );
	}


	/**
	 * Checks if the current post has a special post format.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_post_format( $ret, $rule ): bool {

		$query = $rule->get_query();

		if ( ! $query->is_singular() ) {
			return false;
		}

		$current_post = $query->post;

		if ( ! is_a( $current_post, '\WP_Post' ) ) {
			return false;
		}

		return $rule->compare( get_post_format( $current_post ) );
	}

	/**
	 * Checks if the current page is a specific user.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.29.0
	 */
	public static function match_user( $ret, $rule ): bool {

		$query = $rule->get_query();

		if ( '==' === $rule->operator ) {
			if ( $query->is_author( (int) $rule->value ) ) {
				return true;
			}
		} else {
			if ( ! $query->is_author( (int) $rule->value ) ) {
				return true;
			}
		}

		if ( $query->is_singular() ) {
			if ( '==' === $rule->operator ) {
				return (int) $query->queried_object->post_author === (int) $rule->value;
			} else {
				return (int) $query->queried_object->post_author !== (int) $rule->value;
			}
		}

		return false;
	}


	/**
	 * Check if any of the terms is a child of a given term.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.10.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_child_terms( $ret, $rule ): bool {
		# extract the taxonomy
		$taxonomy = strstr( $rule->value, ':', true );

		# remove taxonomy from the value and make to INT
		$term_id     = absint( str_replace( $taxonomy . ':', '', $rule->value ) );
		$rule->value = $term_id;

		$query = $rule->get_query();

		if ( ! $query->is_singular() ) {
			return false;
		}

		$current_post = $query->post;

		if ( ! is_a( $current_post, '\WP_Post' ) ) {
			return false;
		}

		$post_terms = get_terms( [ 'object_ids' => $current_post->ID, 'taxonomy' => $taxonomy ] );

		if ( ! is_array( $post_terms ) ) {
			return false;
		}

		$i = 0;

		foreach ( $post_terms as $post_term ) {
			if ( empty( $post_term->parent ) ) {
				continue;
			}

			if ( term_is_ancestor_of( $rule->value, $post_term->term_id, $taxonomy ) ) {
				$i ++;

				if ( '==' === $rule->operator ) {
					return true;
				}
			}

		}

		if ( '!=' === $rule->operator && $i <= 0 ) {
			return true;
		}

		return false;
	}


	/**
	 * Checks if a current post has a specific taxonomy.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_post_taxonomy( $ret, $rule ): bool {

		# extract the post type
		$taxonomy = strstr( $rule->value, ':', true );

		# remove taxonomy from the value and make to INT
		$rule->value = absint( str_replace( $taxonomy . ':', '', $rule->value ) );

		return $rule->match_term( $taxonomy );
	}


	/**
	 * Match a page template.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_page_template( $ret, $rule ): bool {

		$rule->value = 'page:' . $rule->value;

		return self::match_post_template( $ret, $rule, 'page' );
	}

	/**
	 * Compares a page type (and any special pages).
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_page_type( $ret, $rule ): bool {

		$query = $rule->get_query();

		$current_page = '';

		if ( 'all' === $rule->value ) {
			$current_page = $rule->value;
		} elseif ( 'author' === $rule->value ) {
			if ( $query->is_author() ) {
				$current_page = 'author';
			}
		} elseif ( 'top_level' === $rule->value ) {
			# check if current post is a top level post

			$current_post = $query->post;

			if ( ! is_a( $current_post, '\WP_Post' ) ) {
				return false;
			}

			$current_page = empty( $current_post->post_parent ) ? 'top_level' : 'sub_level';

		} elseif ( 'parent' === $rule->value ) {
			# check if current post has children

			$current_post = $query->post;

			if ( ! is_a( $current_post, '\WP_Post' ) ) {
				return false;
			}

			$children = get_posts( array(
				'post_type'      => $current_post->post_type,
				'post_parent'    => $current_post->ID,
				'posts_per_page' => 1,
				'fields'         => 'ids',
			) );

			$current_page = count( $children ) > 0 ? 'parent' : 'no_parent';
		} elseif ( 'child' === $rule->value ) {
			# check if the current post has a parent

			$current_post = $query->post;

			if ( ! is_a( $current_post, '\WP_Post' ) ) {
				return false;
			}

			$current_page = ! empty( $current_post->post_parent ) ? 'child' : 'no_child';
		} elseif ( $query->is_front_page() ) {
			$current_page = 'front_page';
		} elseif ( $query->is_home() ) {
			$current_page = 'posts_page';
		} elseif ( $query->is_post_type_archive() ) {
			$current_page = 'archive_' . $query->get( 'post_type' );
		} elseif ( $query->is_archive() && 'archive' === $rule->value ) {
			$current_page = 'archive';
		} elseif ( $query->is_category() ) {
			# Note: is_tax() does not return TRUE for category archive pages.
			# @see https://codex.wordpress.org/Function_Reference/is_tax
			$current_page = 'archive_category';
		} elseif ( $query->is_tag() ) {
			# Note: is_tax() does not return TRUE for tag archive pages.
			# @see https://codex.wordpress.org/Function_Reference/is_tax
			$current_page = 'archive_post_tag';
		} elseif ( $query->is_tax() ) {
			$taxonomy = $query->get_queried_object();
			if ( $taxonomy instanceof \WP_Term ) {
				$current_page = 'archive_' . $taxonomy->taxonomy;
			}
		} elseif ( $query->is_search() ) {
			$current_page = 'search';
		}

		return $rule->compare( $current_page );
	}


	/**
	 * Checks if the current page has a particular parent page.
	 *
	 * @param bool $ret
	 * @param Position_Rule $rule
	 *
	 * @return bool
	 * @since 2.0.0
	 * @since 2.19.14 moved to pro\Admin_Position_Controller
	 * @since 2.19.18 moved to pro\Rules_Model
	 */
	public static function match_page_parent( $ret, $rule ): bool {

		$query = $rule->get_query();

		if ( ! $query->is_singular() ) {
			return false;
		}

		$current_post = $query->post;

		if ( ! is_a( $current_post, '\WP_Post' ) ) {
			return false;
		}

		$rule->value = absint( $rule->value );

		return $rule->compare( $current_post->post_parent );
	}


}
