<?php
/**
 * BricksExtras Dynamic Tags using Bricks Filters
 *
 * Replaces the custom provider system with Bricks Filters.
 *
 * @package BricksExtras
 */

namespace BricksExtras;

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

/**
 * BricksExtrasDynamicTags class for managing dynamic tags via Bricks native filters.
 */
class BricksExtrasDynamicTags {

	/**
	 * Initialize the dynamic tags.
	 *
	 * @return void
	 */
	public static function init() {
		// Register tags in builder.
		add_filter( 'bricks/dynamic_tags_list', array( __CLASS__, 'register_tags_in_builder' ) );

		// Handle individual tag rendering.
		add_filter( 'bricks/dynamic_data/render_tag', array( __CLASS__, 'render_tag' ), 20, 3 );

		// Process content for our dynamic tags. Replace in content.
		add_filter( 'bricks/dynamic_data/render_content', array( __CLASS__, 'render_content' ), 20, 3 );
		add_filter( 'bricks/frontend/render_data', array( __CLASS__, 'render_content' ), 20, 2 );
	}

	/**
	 * Register tags in the builder.
	 *
	 * @param array $tags Existing tags.
	 * @return array Modified tags array.
	 */
	public static function register_tags_in_builder( $tags ) {

		$extras_group = esc_html__( 'Extras', 'bricks' );

		$custom_tags = array(
			// Post tags.
			array(
				'name'  => '{x_post_reading_time}',
				'label' => esc_html__( 'Post reading time', 'bricksextras' ) . ' (extras)',
				'group' => esc_html__( 'Post', 'bricks' ),
			),
			array(
				'name'  => '{x_post_terms_list}',
				'label' => esc_html__( 'Post terms list', 'bricksextras' ) . ' (extras)',
				'group' => esc_html__( 'Post', 'bricks' ),
			),

			// General extras.
			array(
				'name'  => '{x_url_parameter}',
				'label' => esc_html__( 'URL parameter', 'bricks' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_est_year_current_year}',
				'label' => esc_html__( 'Est. year - current year', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_loop_index}',
				'label' => esc_html__( 'Loop index', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_parent_loop_index}',
				'label' => esc_html__( 'Parent loop index', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),

			// Menu items.
			array(
				'name'  => '{x_menu_item_label}',
				'label' => esc_html__( 'Menu Item Label', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_menu_item_url}',
				'label' => esc_html__( 'Menu Item URL', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_menu_item_description}',
				'label' => esc_html__( 'Menu Item Description', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_menu_item_classes}',
				'label' => esc_html__( 'Menu Item Classes', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_menu_item_target}',
				'label' => esc_html__( 'Menu Item Target', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_menu_item_id}',
				'label' => esc_html__( 'Menu Item ID', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),

			// Favorites.
			array(
				'name'  => '{x_favorite_ids}',
				'label' => esc_html__( 'Favorite IDs', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_favorite_count}',
				'label' => esc_html__( 'Favorite Count', 'bricksextras' ) . ' (' . esc_html__( 'Display', 'bricks' ) . ') (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_favorite_count_number}',
				'label' => esc_html__( 'Favorite Count', 'bricksextras' ) . ' (' . esc_html__( 'Number', 'bricks' ) . ') (extras)',
				'group' => $extras_group,
			),

			// Attachment tags.
			array(
				'name'  => '{x_attachment_alt_text}',
				'label' => esc_html__( 'Attachment Alt Text', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_attachment_title}',
				'label' => esc_html__( 'Attachment Title', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_attachment_url}',
				'label' => esc_html__( 'Attachment File URL', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_attachment_description}',
				'label' => esc_html__( 'Attachment Description', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
			array(
				'name'  => '{x_attachment_caption}',
				'label' => esc_html__( 'Attachment Caption', 'bricksextras' ) . ' (extras)',
				'group' => $extras_group,
			),
		);

		return array_merge( $tags, $custom_tags );
	}

	/**
	 * Render individual tag.
	 *
	 * @param string   $tag     Tag with curly braces.
	 * @param \WP_Post $post    Post object.
	 * @param string   $context Context.
	 * @return string|mixed Rendered value or original tag.
	 */
	public static function render_tag( $tag, $post, $context = 'text' ) {
		if ( ! is_string( $tag ) ) {
			return $tag;
		}

		// Remove curly braces.
		$clean_tag = str_replace( array( '{', '}' ), '', $tag );

		// Parse tag and arguments (handles filters like x_post_reading_time:minute,minutes,225).
		$parsed   = self::parse_tag_arguments( $clean_tag );
		$tag_name = $parsed['tag'];
		$args     = $parsed['args'];

		// Check if this is one of our tags.
		if ( ! self::is_our_tag( $tag_name ) ) {
			return $tag;
		}

		// Get the tag value.
		$value = self::get_tag_value( $tag_name, $post, $args, $context );

		return false !== $value ? $value : $tag;
	}

	/**
	 * Render content with multiple tags.
	 *
	 * @param string   $content Content to process.
	 * @param \WP_Post $post    Post object.
	 * @param string   $context Context.
	 * @return string Processed content.
	 */
	public static function render_content( $content, $post, $context = 'text' ) {
		// Pattern to match our tags with arguments.
		$pattern = '/{(x_[^}]+)}/';

		preg_match_all( $pattern, $content, $matches );

		if ( empty( $matches[0] ) ) {
			return $content;
		}

		foreach ( $matches[1] as $key => $match ) {
			$full_tag = $matches[0][ $key ];

			// Parse tag and arguments.
			$parsed   = self::parse_tag_arguments( $match );
			$tag_name = $parsed['tag'];
			$args     = $parsed['args'];

			// Check if this is one of our tags.
			if ( ! self::is_our_tag( $tag_name ) ) {
				continue;
			}

			// Get the tag value.
			$value = self::get_tag_value( $tag_name, $post, $args, $context );

			if ( false !== $value ) {
				// Convert arrays to string format for content replacement.
				if ( is_array( $value ) ) {
					$value = '[' . implode( ', ', $value ) . ']';
				}
				$content = str_replace( $full_tag, $value, $content );
			}
		}

		return $content;
	}

	/**
	 * Parse tag arguments (filters).
	 *
	 * @param string $tag_string Full tag string with potential arguments.
	 * @return array Array with 'tag' and 'args'.
	 */
	private static function parse_tag_arguments( $tag_string ) {

		// Handle arguments like x_post_reading_time:minute,minutes,225.
		if ( false !== strpos( $tag_string, ':' ) ) {
			$parts       = explode( ':', $tag_string, 2 );
			$tag         = $parts[0];
			$args_string = $parts[1];

			$args = array(
				'meta_key' => $args_string,
			);

			// Handle num_words parameter (used by some tags).
			if ( in_array( $tag, array( 'x_loop_index', 'x_parent_loop_index', 'x_est_year_current_year' ), true ) ) {
				$args['num_words'] = $args_string;
			}
		} else {
			$tag  = $tag_string;
			$args = array();
		}

		return array(
			'tag'  => $tag,
			'args' => $args,
		);
	}

	/**
	 * Check if tag belongs to our system.
	 *
	 * @param string $tag_name Tag name without braces.
	 * @return bool True if our tag.
	 */
	private static function is_our_tag( $tag_name ) {
		$our_tags = array(
			'x_post_reading_time',
			'x_post_terms_list',
			'x_url_parameter',
			'x_est_year_current_year',
			'x_loop_index',
			'x_parent_loop_index',
			'x_menu_item_label',
			'x_menu_item_url',
			'x_menu_item_description',
			'x_menu_item_classes',
			'x_menu_item_target',
			'x_menu_item_id',
			'x_favorite_ids',
			'x_favorite_count',
			'x_favorite_count_number',
			'x_attachment_alt_text',
			'x_attachment_title',
			'x_attachment_url',
			'x_attachment_description',
			'x_attachment_caption',
		);

		return in_array( $tag_name, $our_tags, true );
	}

	/**
	 * Get tag value - reuses existing logic from Provider_Extras.
	 *
	 * @param string   $tag     Tag name.
	 * @param \WP_Post $post    Post object.
	 * @param array    $args    Arguments.
	 * @param string   $context Context.
	 * @return string|false Tag value or false if not found.
	 */
	private static function get_tag_value( $tag, $post, $args, $context ) {
		$value = '';

		// Create filters array in the format expected by existing code.
		$filters = array();
		if ( isset( $args['meta_key'] ) ) {
			$filters['meta_key'] = $args['meta_key'];
		}
		if ( isset( $args['num_words'] ) ) {
			$filters['num_words'] = $args['num_words'];
		}

		switch ( $tag ) {
			case 'x_post_reading_time':
				if ( ! empty( $filters['meta_key'] ) ) {
					$meta_keys           = explode( ',', $filters['meta_key'] );
					$text_after_singular = isset( $meta_keys[0] ) ? $meta_keys[0] : 'minute';
					$text_after_plural   = isset( $meta_keys[1] ) ? $meta_keys[1] : 'minutes';
					$wpm                 = isset( $meta_keys[2] ) ? intval( trim( $meta_keys[2] ) ) : 225;
				} else {
					$text_after_singular = 'minute';
					$text_after_plural   = 'minutes';
					$wpm                 = 225;
				}

				if ( null !== $post ) {
					$content    = get_post_field( 'post_content', $post->ID );
					$word_array = preg_split( '/\s+/', wp_strip_all_tags( $content ) );
					$word_count = is_array( $word_array ) ? count( $word_array ) : 0;

					$readingtime = intval( ceil( $word_count / $wpm ) );

					if ( 1 === $readingtime ) {
						$timer = ' ' . $text_after_singular;
					} else {
						$timer = ' ' . $text_after_plural;
					}

					$value = esc_html( $readingtime . $timer );
				}
				break;

			case 'x_post_terms_list':
				if ( ! empty( $filters['meta_key'] ) ) {
					$taxonomy = isset( $filters['meta_key'] ) ? sanitize_text_field( $filters['meta_key'] ) : '';
				} else {
					$taxonomy = 'category';
				}

				$term_list = get_the_term_list( $post->ID, $taxonomy, '', ', ' );
				$value     = is_string( $term_list ) ? esc_html( wp_strip_all_tags( $term_list ) ) : '';
				break;

			case 'x_url_parameter':
				if ( ! empty( $filters['meta_key'] ) ) {
					$variable = isset( $filters['meta_key'] ) ? sanitize_text_field( $filters['meta_key'] ) : '';
				} else {
					$variable = 's';
				}
				$value = esc_html( \BricksExtras\Helpers::get_get_value( $variable ) );
				break;

			case 'x_est_year_current_year':
				if ( ! empty( $filters['num_words'] ) ) {
					$est_year = isset( $filters['num_words'] ) ? sanitize_text_field( $filters['num_words'] ) : false;
					if ( false !== $est_year ) {
						$value = date( 'Y' ) === $est_year ? date( 'Y' ) : esc_html( $est_year . ' - ' . date( 'Y' ) );
					}
				} else {
					$value = date( 'Y' );
				}
				break;

			case 'x_loop_index':
				if ( method_exists( '\Bricks\Query', 'get_query_object' ) ) {
					$query_object = \Bricks\Query::get_query_object();
					if ( $query_object ) {
						$offset = isset( $filters['num_words'] ) ? sanitize_text_field( $filters['num_words'] ) : 0;
						$value  = intval( $query_object::get_loop_index() ) + $offset;
					}
				}
				break;

			case 'x_parent_loop_index':
				if ( method_exists( '\Bricks\Query', 'get_query_for_element_id' ) ) {
					$level = isset( $filters['num_words'] ) ? sanitize_text_field( $filters['num_words'] ) : 1;
					$value = \BricksExtras\Helpers::get_bricks_looping_parent_query_id_by_level( $level ) ? intval( \Bricks\Query::get_query_for_element_id( \Bricks\Query::get_query_element_id( \BricksExtras\Helpers::get_bricks_looping_parent_query_id_by_level( $level ) ) )->loop_index ) : '';
				}
				break;

			// Menu items.
			case 'x_menu_item_label':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) ) {
							$value = wp_kses_post( $loop_object->title );
						}
					}
				}
				break;

			case 'x_menu_item_url':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) ) {
							$value = esc_url( $loop_object->url );
						}
					}
				}
				break;

			case 'x_menu_item_description':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) ) {
							$value = wp_kses_post( $loop_object->description );
						}
					}
				}
				break;

			case 'x_menu_item_classes':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) && is_array( $loop_object->classes ) ) {
							$as_string = implode( ' ', $loop_object->classes );
							$value     = '' !== $as_string ? esc_attr( $as_string ) : '';
						}
					}
				}
				break;

			case 'x_menu_item_target':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) ) {
							$value = $loop_object->target ? esc_attr( $loop_object->target ) : '_self';
						}
					}
				}
				break;

			case 'x_menu_item_id':
				if ( method_exists( '\Bricks\Query', 'is_any_looping' ) ) {
					$looping_query_id = \Bricks\Query::is_any_looping();
					if ( $looping_query_id ) {
						$loop_object = \Bricks\Query::get_loop_object( $looping_query_id );
						if ( $loop_object && is_object( $loop_object ) ) {
							$value = isset( $loop_object->ID ) ? intval( $loop_object->ID ) : '';
						}
					}
				}
				break;

			// Favorites.
			case 'x_favorite_ids':
				$list = isset( $filters['meta_key'] ) ? sanitize_text_field( $filters['meta_key'] ) : 'post';

				$array = \BricksExtras\Helpers::get_favorite_ids_array( $list );

				if ( empty( $array ) ) {
					$value = '[0]';
				} else {
					$string = implode( ', ', $array );
					$value  = esc_html( '[' . $string . ']' );
				}

				break;

			case 'x_favorite_count':
				$list = isset( $filters['meta_key'] ) ? sanitize_text_field( $filters['meta_key'] ) : 'post';

				// Check if the list contains multiple values separated by colon.
				if ( false !== strpos( $list, ':' ) ) {
					$lists = explode( ':', $list );
					$array = array();

					// Get IDs for each list and merge them.
					foreach ( $lists as $single_list ) {
						$single_list = trim( $single_list );
						$list_array  = \BricksExtras\Helpers::get_favorite_ids_array( $single_list );
						if ( ! empty( $list_array ) && is_array( $list_array ) ) {
							$array = array_merge( $array, $list_array );
						}
					}
				} else {
					// Original behavior for a single list.
					$array = \BricksExtras\Helpers::get_favorite_ids_array( $list );
				}

				if ( empty( $array ) ) {
					$count = '';
				} else {
					$count = count( $array );
				}

				$value = '<span data-x-favorite-count="' . esc_attr( $list ) . '">' . intval( $count ) . '</span>';
				break;

			case 'x_favorite_count_number':
				$list = isset( $filters['meta_key'] ) ? sanitize_text_field( $filters['meta_key'] ) : 'post';

				// Check if the list contains multiple values separated by colon.
				if ( false !== strpos( $list, ':' ) ) {
					$lists = explode( ':', $list );
					$array = array();

					// Get IDs for each list and merge them.
					foreach ( $lists as $single_list ) {
						$single_list = trim( $single_list );
						$list_array  = \BricksExtras\Helpers::get_favorite_ids_array( $single_list );
						if ( ! empty( $list_array ) && is_array( $list_array ) ) {
							$array = array_merge( $array, $list_array );
						}
					}
				} else {
					// Original behavior for a single list.
					$array = \BricksExtras\Helpers::get_favorite_ids_array( $list );
				}

				if ( empty( $array ) ) {
					$count = 0;
				} else {
					$count = count( $array );
				}

				$value = intval( $count );
				break;

			case 'x_attachment_alt_text':
				$alt   = trim( wp_strip_all_tags( get_post_meta( \Bricks\Query::get_loop_object_id(), '_wp_attachment_image_alt', true ) ) );
				$value = esc_attr( $alt );
				break;

			case 'x_attachment_title':
				$title = get_the_title( \Bricks\Query::get_loop_object_id() );
				$value = wp_kses_post( $title );
				break;

			case 'x_attachment_url':
				$url   = wp_get_attachment_url( get_the_ID() );
				$value = $url ? esc_url( $url ) : '';
				break;

			case 'x_attachment_description':
				$description = get_post( \Bricks\Query::get_loop_object_id() )->post_content;
				$value       = wp_kses_post( $description );
				break;

			case 'x_attachment_caption':
				$caption = wp_get_attachment_caption( \Bricks\Query::get_loop_object_id() );
				$value   = wp_kses_post( $caption );
				break;
		}

		return $value;
	}
}
