<?php
/**
 * Static singleton class for presets functions.
 *
 * @package xts
 */

namespace XTS;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Direct access not allowed.
}

use XTS\Options;
use XTS\Singleton;

/**
 * Create presets post type and functionality.
 */
class Presets extends Singleton {

	/**
	 * All presets.
	 *
	 * @var array
	 */
	private static $presets;

	/**
	 * Register hooks and load base data.
	 *
	 * @since 1.0.0
	 */
	public function init() {
		add_action( 'wp_ajax_xts_new_preset_action', array( $this, 'new_preset_action' ) );
		add_action( 'wp_ajax_xts_remove_preset_action', array( $this, 'remove_preset_action' ) );
		add_action( 'wp_ajax_xts_save_preset_conditions_action', array( $this, 'save_preset_conditions_action' ) );
		add_action( 'wp_ajax_xts_save_preset_conditions_action', array( $this, 'save_preset_conditions_action' ) );
		add_action( 'wp_ajax_xts_get_entity_ids_action', array( $this, 'get_entity_ids_action' ) );

		$this->load_presets();
	}

	/**
	 * Load presets from the database.
	 *
	 * @since 1.0.0
	 */
	public function load_presets() {
		$presets = get_option( 'xts-options-presets' );

		if ( ! $presets || empty( $presets ) ) {
			$presets = array();
		}

		self::$presets = $presets;
	}

	/**
	 * AJAX action for saving preset conditions.
	 *
	 * @since 1.0.0
	 */
	public function save_preset_conditions_action() {

		check_ajax_referer( 'xts-preset-form', 'security' );

		$id = isset( $_POST['preset'] ) ? (int) sanitize_text_field( $_POST['preset'] ) : false; // phpcs:ignore

		$condition = array(
			'relation' => 'OR',
			'rules'    => array(),
		);

		if ( $id && isset( $_POST['data'] ) && is_array( $_POST['data'] ) ) {
			foreach ( $_POST['data'] as $key => $rule ) { // phpcs:ignore
				$condition['rules'][] = wp_parse_args(
					$rule,
					array(
						'type'       => '',
						'comparison' => '=',
						'post_type'  => '',
						'taxonomy'   => '',
						'custom'     => '',
						'value_id'   => '',
					)
				);
			}
		}

		$this->update_preset_conditions( $id, $condition );

		$this->ajax_response();

		wp_die();
	}

	/**
	 * Update preset conditions.
	 *
	 * @since 1.0.0
	 *
	 * @param array $id        Preset's id.
	 * @param array $condition Conditions array.
	 */
	public function update_preset_conditions( $id, $condition ) {
		self::$presets[ $id ]['condition'] = $condition;

		$this->update_presets();
	}

	/**
	 * Create preset AJAX action.
	 *
	 * @since 1.0.0
	 */
	public function new_preset_action() {

		check_ajax_referer( 'xts-preset-form', 'security' );

		$name = isset( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : 'New preset'; // phpcs:ignore

		$id = $this->add_preset( $name );

		$this->ajax_response(
			array(
				'id' => $id,
			)
		);

		wp_die();
	}

	/**
	 * Remove preset AJAX action.
	 *
	 * @since 1.0.0
	 */
	public function remove_preset_action() {

		check_ajax_referer( 'xts-preset-form', 'security' );

		$id = isset( $_POST['id'] ) ? (int) sanitize_text_field( $_POST['id'] ) : false; // phpcs:ignore

		if ( ! $id ) {
			wp_die();
		}

		$this->remove_preset( $id );

		$this->ajax_response();

		wp_die();
	}

	/**
	 * Create a preset in the database.
	 *
	 * @since 1.0.0
	 *
	 * @param array $name Preset name.
	 */
	public function add_preset( $name ) {
		$all = self::get_all();

		end( $all );

		$last_id = key( $all );

		if ( empty( $all ) ) {
			$last_id = 0;
		}

		$id = $last_id + 1;

		$new_preset = array(
			'id'        => $id,
			'name'      => $name,
			'condition' => array(),
		);

		self::$presets[ $id ] = $new_preset;

		$this->update_presets();

		return $id;
	}

	/**
	 * Remove preset from the database.
	 *
	 * @since 1.0.0
	 *
	 * @param array $id Remove preset by id.
	 */
	public function remove_preset( $id ) {

		if ( ! isset( self::$presets[ $id ] ) ) {
			return;
		}

		unset( self::$presets[ $id ] );

		$this->update_presets();
	}

	/**
	 * Update presets option.
	 *
	 * @since 1.0.0
	 */
	public function update_presets() {
		update_option( 'xts-options-presets', self::$presets );
	}

	/**
	 * Send AJAX response data.
	 *
	 * @since 1.0.0
	 *
	 * @param array $data Additional data array.
	 */
	public function ajax_response( $data = array() ) {

		ob_start();
		self::output_ui();
		$ui = ob_get_clean();

		echo wp_json_encode(
			array_merge(
				array(
					'ui' => $ui,
				),
				$data
			)
		);
	}

	/**
	 * AJAX action to load entities names.
	 *
	 * @since 1.0.0
	 */
	public function get_entity_ids_action() {
		check_ajax_referer( 'xts-preset-form', 'security' );

		$type = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : false; // phpcs:ignore
		$name = isset( $_POST['name'] ) ? sanitize_text_field( $_POST['name'] ) : false; // phpcs:ignore

		$items = array();

		switch ( $type ) {
			case 'term_id':
				$args = array(
					'hide_empty' => false,
					'fields'     => 'all',
					'name__like' => $name,
				);

				$terms = get_terms( $args );

				if ( count( $terms ) > 0 ) {
					foreach ( $terms as $term ) {
						$items[] = array(
							'id'   => $term->term_id,
							'text' => $term->name,
						);
					}
				}
				break;
			case 'post_id':
				$args = array(
					's'              => $name,
					'post_type'      => get_post_types( array( 'public' => true ) ),
					'posts_per_page' => 100,
				);

				$posts = get_posts( $args );

				if ( count( $posts ) > 0 ) {
					foreach ( $posts as $post ) {
						$items[] = array(
							'id'   => $post->ID,
							'text' => $post->post_title,
						);
					}
				}
				break;
		}

		echo wp_json_encode(
			array(
				'results' => $items,
			)
		);

		wp_die();
	}

	/**
	 * Output Presets UI.
	 *
	 * @since 1.0.0
	 */
	public static function output_ui() {
		?>
			<div class="xts-presets-wrapper" data-current-id="<?php echo esc_attr( self::get_current_preset() ); ?>" data-preset-url="<?php echo esc_url( admin_url( 'admin.php?page=xtemos_options&preset=' ) ); ?>" data-base-url="<?php echo esc_url( admin_url( 'admin.php?page=xtemos_options' ) ); ?>">
				<div class="xts-presets-inner">
					<?php if ( self::get_current_preset() ) : ?>
						<div class="xts-current-preset">
							<h3><?php echo esc_html( self::$presets[ self::get_current_preset() ]['name'] ); ?></h3>
							<div class="xts-preset-conditions">
								<strong><?php esc_html_e( 'Conditions', 'xts-theme' ); ?></strong>
								<form action="">
									<?php self::display_current_conditions(); ?>
									<a href="#" class="xts-add-preset-rule">+</a>
									<?php wp_nonce_field( 'xts-preset-form' ); ?>
									<div>
										<button type="submit"><?php esc_html_e( 'Save conditions', 'xts-theme' ); ?></button>
									</div>
								</form>
							</div>
						</div>
						<div class="xts-rule-template">
							<?php self::rule_template(); ?>
						</div>
					<?php else : ?>
						<?php wp_nonce_field( 'xts-preset-form' ); ?>
					<?php endif; ?>
					<div class="xts-presets-list">

						<?php if ( is_array( self::$presets ) && count( self::$presets ) ) : ?>
							<h3><?php esc_html_e( 'Options presets', 'xts-theme' ); ?></h3>
							<?php foreach ( self::$presets as $id => $preset ) : ?>
								<div>
									<a href="<?php echo esc_url( admin_url( 'admin.php?page=xtemos_options&preset=' . $id ) ); ?>">
										<?php echo esc_html( $preset['name'] ); ?>
									</a>
									<a href="#" class="xts-remove-preset-btn" data-id="<?php echo esc_attr( $id ); ?>">x</a>
								</div>
							<?php endforeach; ?>
						<?php else : ?>
							<p><?php esc_html_e( 'There are no custom presets yet.', 'xts-theme' ); ?></p>
						<?php endif; ?>

						<button class="xts-add-new-preset"><?php esc_html_e( 'Create a new preset', 'xts-theme' ); ?></button>

						<?php ar( self::$presets ); ?>
					</div>
				</div>
			</div>
		<?php
	}

	/**
	 * Display current preset conditions form.
	 *
	 * @since 1.0.0
	 */
	public static function display_current_conditions() {
		$preset    = self::$presets[ self::get_current_preset() ];
		$condition = $preset['condition'];

		?>
			<div class="xts-condition-rules">
		<?php
		if ( ! empty( $condition['rules'] ) ) {
			foreach ( $condition['rules'] as $rule ) {
				self::rule_template( false, $rule );
			}
		} else {
			self::rule_template( false );
		}
		?>
			</div>
		<?php
	}

	/**
	 * HTML template for one rule.
	 *
	 * @since 1.0.0
	 *
	 * @param array $hidden Is this template hidden.
	 * @param array $rule   Rule array.
	 */
	public static function rule_template( $hidden = true, $rule = array() ) {

		$rule = wp_parse_args(
			$rule,
			array(
				'type'       => '',
				'comparison' => '=',
				'post_type'  => '',
				'taxonomy'   => '',
				'custom'     => '',
				'value_id'   => '',
			)
		);

		$post_types = get_post_types(
			array(
				'public' => true,
			)
		);

		$taxonomies = get_taxonomies(
			array(
				'public' => true,
			)
		);

		$custom_conditions = apply_filters(
			'xts_get_custom_conditions_for_preset',
			array(
				'search'         => 'Search results',
				'blog'           => 'Default "Your Latest Posts" screen',
				'front'          => 'Front page',
				'archives'       => 'All archives',
				'author'         => 'Author archives',
				'error404'       => '404 error screens',
				'shop'           => 'Shop page',
				'single_product' => 'Single product',
				'cart'           => 'Cart page',
				'checkout'       => 'Checkout page',
				'account'        => 'Account pages',
			)
		);

		$title = false;

		if ( 'post_id' === $rule['type'] && ! empty( $rule['value_id'] ) ) {
			$title = get_the_title( $rule['value_id'] );
		}

		if ( 'term_id' === $rule['type'] && ! empty( $rule['value_id'] ) ) {
			$term_object = false;

			$taxonomies = get_taxonomies();

			foreach ( $taxonomies as $tax_type_key => $taxonomy ) {
				$term_object = get_term_by( 'id', $rule['value_id'], $taxonomy );
				if ( ! $term_object ) {
					break;
				}
			}

			if ( $term_object ) {
				$title = $term_object->name;
			}
		}

		?>
			<div class="xts-rule <?php echo $hidden ? 'xts-hidden' : ''; ?>">
				<select class="xts-rule-type">
					<option value=""><?php esc_html_e( '--type--', 'xts-theme' ); ?></option>
					<option value="post_type" <?php selected( 'post_type', $rule['type'] ); ?>><?php esc_html_e( 'Post type', 'xts-theme' ); ?></option>
					<option value="post_id" <?php selected( 'post_id', $rule['type'] ); ?>><?php esc_html_e( 'Post ID', 'xts-theme' ); ?></option>
					<option value="taxonomy" <?php selected( 'taxonomy', $rule['type'] ); ?>><?php esc_html_e( 'Taxonomy', 'xts-theme' ); ?></option>
					<option value="term_id" <?php selected( 'term_id', $rule['type'] ); ?>><?php esc_html_e( 'Term ID', 'xts-theme' ); ?></option>
					<option value="custom" <?php selected( 'custom', $rule['type'] ); ?>><?php esc_html_e( 'Custom', 'xts-theme' ); ?></option>
				</select>
				<select class="xts-rule-comparison">
					<option value="equals" <?php selected( 'equals', $rule['comparison'] ); ?>><?php esc_html_e( 'equals', 'xts-theme' ); ?></option>
					<option value="not_equals" <?php selected( 'not_equals', $rule['comparison'] ); ?>><?php esc_html_e( 'not equals', 'xts-theme' ); ?></option>
				</select>
				<select class="xts-rule-post-type <?php echo 'post_type' !== $rule['type'] ? 'xts-hidden' : ''; ?>">
					<?php foreach ( $post_types as $key => $type ) : ?>
						<option value="<?php echo esc_attr( $type ); ?>" <?php selected( $type, $rule['post_type'] ); ?>><?php echo esc_html( $type ); ?></option>
					<?php endforeach; ?>
				</select>
				<select class="xts-rule-taxonomy <?php echo 'taxonomy' !== $rule['type'] ? 'xts-hidden' : ''; ?>">
					<?php foreach ( $taxonomies as $key => $taxonomy ) : ?>
						<option value="<?php echo esc_attr( $taxonomy ); ?>" <?php selected( $taxonomy, $rule['taxonomy'] ); ?>><?php echo esc_html( $taxonomy ); ?></option>
					<?php endforeach; ?>
				</select>
				<select class="xts-rule-custom <?php echo 'custom' !== $rule['type'] ? 'xts-hidden' : ''; ?>">
					<?php foreach ( $custom_conditions as $key => $condition ) : ?>
						<option value="<?php echo esc_attr( $key ); ?>" <?php selected( $key, $rule['custom'] ); ?>><?php echo esc_html( $condition ); ?></option>
					<?php endforeach; ?>
				</select>

				<div class="xts-rule-value-wrapper <?php echo 'post_id' !== $rule['type'] && 'term_id' !== $rule['type'] ? 'xts-hidden' : ''; ?>">
					<select data-placeholder="<?php esc_attr_e( 'Start typing...', 'xts-theme' ); ?>" class="xts-rule-value-id" data-value="<?php echo esc_attr( $rule['value_id'] ); ?>">
						<?php if ( $title ) : ?>
							<option value="<?php echo esc_attr( $rule['value_id'] ); ?>" selected="selected"><?php echo esc_html( $title ); ?></option>
						<?php endif; ?>
					</select>
				</div>
				<a href="#" class="xts-remove-preset-rule">x</a>
			</div>
		<?php
	}

	/**
	 * Get currently editing preset.
	 *
	 * @since 1.0.0
	 */
	public static function get_current_preset() {
		return isset( $_REQUEST['preset'] ) && isset( self::$presets[ $_REQUEST['preset'] ] ) ? intval( $_REQUEST['preset'] ) : false; // phpcs:ignore
	}

	/**
	 * Presets getter.
	 *
	 * @since 1.0.0
	 */
	public static function get_all() {
		return self::$presets;
	}

	/**
	 * Get presets that active for the current page.
	 *
	 * @since 1.0.0
	 */
	public static function get_active_presets() {
		$all = self::get_all();

		$active_presets = array();

		foreach ( $all as $preset ) {
			if ( empty( $preset['condition'] ) || ! isset( $preset['condition']['rules'] ) || empty( $preset['condition']['rules'] ) ) {
				continue;
			}

			$rules = $preset['condition']['rules'];
			foreach ( $rules as $rule ) {
				$is_active = false;
				switch ( $rule['type'] ) {
					case 'post_type':
						$condition = get_post_type() === $rule['post_type'];
						$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
						break;
					case 'post_id':
						$condition = get_the_ID() == $rule['value_id'];
						$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
						break;
					case 'term_id':
						$object  = get_queried_object();
						$term_id = is_object( $object ) && property_exists( $object, 'term_id' ) ? get_queried_object()->term_id : false;

						if ( $term_id ) {
							$condition = $term_id == $rule['value_id'];
							$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
						}
						break;
					case 'taxonomy':
						$object = get_queried_object();

						$taxonomy = is_object( $object ) && property_exists( $object, 'taxonomy' ) ? get_queried_object()->taxonomy : false;

						if ( $taxonomy ) {
							$condition = $taxonomy == $rule['taxonomy'];
							$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
						}
						break;
					case 'custom':
						switch ( $rule['custom'] ) {
							case 'search':
								$is_active = 'equals' === $rule['comparison'] ? is_search() : ! is_search();
								break;
							case 'blog':
								$condition = xts_get_page_id() == get_option( 'page_for_posts' );
								$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
								break;
							case 'front':
								$condition = xts_get_page_id() == get_option( 'page_on_front' );
								$is_active = 'equals' === $rule['comparison'] ? $condition : ! $condition;
								break;
							case 'archives':
								$is_active = 'equals' === $rule['comparison'] ? is_archive() : ! is_archive();
								break;
							case 'author':
								$is_active = 'equals' === $rule['comparison'] ? is_author() : ! is_author();
								break;
							case 'error404':
								$is_active = 'equals' === $rule['comparison'] ? is_404() : ! is_404();
								break;
							case 'shop':
								$is_active = 'equals' === $rule['comparison'] ? is_shop() : ! is_shop();
								break;
							case 'single_product':
								$is_active = 'equals' === $rule['comparison'] ? is_product() : ! is_product();
								break;
							case 'cart':
								$is_active = 'equals' === $rule['comparison'] ? is_cart() : ! is_cart();
								break;
							case 'checkout':
								$is_active = 'equals' === $rule['comparison'] ? is_checkout() : ! is_checkout();
								break;
							case 'account':
								$is_active = 'equals' === $rule['comparison'] ? is_account_page() : ! is_account_page();
								break;
						}
						break;
				}

				if ( $is_active ) {
					$active_presets[] = $preset['id'];
				}
			}
		}

		return apply_filters( 'xts_active_options_presets', array_unique( $active_presets ), $all );
	}
}

Presets::get_instance();
