<?php

/**
 * Render Query / Functions
 * $dragblock_queries:
 *  - A list of post/item ids queried from the database
 *  - You can access to each list via the $dragblock_current_query_list_id
 * $dragblock_queries[$dragblock_current_query_list_id] = [post_ids]
 * 
 * $dragblock_current_query_list_id:
 *  - the id of the current active query
 *  - this is updated when a query is executed, along with $dragblock_queries
 * 
 * $dragblock_current_query_list_item_id:
 *  - the id of the current active item in the current active query
 *  - this is updated when a parse method is called
 * 
 * $dragblock_queries[$dragblock_current_query_list_id][$dragblock_current_query_list_item_id] = post_id
 * 
 * $dragblock_query_param_strings is similar to $dragblock_queries but
 * - saving the list of query strings each database query (even the strings are the same)
 * - You can access $dragblock_query_param_strings[$dragblock_current_query_list_id] = query_string
 * 
 * // use this to excluded loaded posts from certain queries
 * $dragblock_loaded_posts['query_param_string'] = [post_ids]
 */
global $dragblock_queries;
global $dragblock_current_query_list_id;
global $dragblock_current_query_list_item_id;
global $dragblock_loaded_posts;
global $dragblock_query_param_strings;

$dragblock_queries = null;
$dragblock_current_query_list_id = null;
$dragblock_current_query_list_item_id = null;
$dragblock_loaded_posts = array();
$dragblock_query_param_strings = array();


// add_action('wp_head', function () {
//     global $dragblock_queries;
//     global $dragblock_current_query_list_id;
//     global $dragblock_current_query_list_item_id;
//     var_dump($dragblock_queries, $dragblock_current_query_list_id, $dragblock_current_query_list_item_id);
//     // die();
// });

/**
 * Render_block_data will keep the order of the block
 * Parent block will be rendered first, then their children will be rendered later
 * 
 * We did not do shortcode here because we could not access the content blocks with render_block_data
 * which is important for use to render shortcodes for the dragblock/text
 * 
 * However, since we moved the content of dragblock/text to attributes, we could really do shorcode here
 * And we really need to do shortcode here because if we escape the block attributes, all shortcodes attrs
 * will be added with &quot;, ex: [x y="1"] => [x y=&quot;1&quot;]
 */
add_filter('render_block_data', 'dragblock_database_collector', 10, 1);
function dragblock_database_collector($parsed_block)
{
	// var_dump('dragblock_database_collector()');

	// do the shortcode here so it will not render shortcodes with its own database queries
	// var_dump($parsed_block['blockName'], $parsed_block['attrs']);
	// process the blocks that have access to the database
	// if (empty($block['attrs']['dragBlockQueries'])) {
	//     return $parsed_block;
	// }
	// only process blocks from our plugins
	if (empty($parsed_block['attrs']['dragBlockClientId'])) {
		return $parsed_block;
	}


	global $dragblock_queries;
	global $dragblock_current_query_list_id;
	global $dragblock_current_query_list_item_id;
	global $dragblock_loaded_posts;
	global $dragblock_query_param_strings;


	// To Respect The Default WP_Query
	// add default query at the beginning
	// so any parse_post will have things to parse
	// even when there is not a get_post happend before.
	if (empty($dragblock_queries)) {
		global $wp_query;
		$dragblock_current_query_list_id = 'default';
		$dragblock_current_query_list_item_id = null;
		$dragblock_queries[$dragblock_current_query_list_id] = array();
		if (property_exists($wp_query, 'posts') && is_array($wp_query->posts)) {
			foreach ($wp_query->posts as $post) {
				array_push($dragblock_queries[$dragblock_current_query_list_id], $post->ID);
			}
		}
	}

	// process the custom queries
	if (empty($parsed_block['attrs']['dragBlockQueries'])) return $parsed_block;



	$count = -1;
	foreach ($parsed_block['attrs']['dragBlockQueries'] as $query) {
		if (!empty($query['disabled']))	continue;


		$slug = $query['slug'];
		$id = $query['id'];

		if (empty($query['params'])) {
			$query['params'] = array();
		}
		$params = $query['params'];


		// listing queries
		if (in_array($slug, array('WP_Query', 'WP_Query_Default'))) {

			$args = array(
				'fields' => 'ids',
				// 'source' => 'dragblock',
			);
			$query_param_string = '';
			$ignore_loaded_posts = false;

			// fill the query arguments
			foreach ($query['params'] as $param) {
				if (!empty($param['disabled']) || $param['value'] === '') {
					continue;
				}

				// array attributes
				$key = $param['slug'];
				$val = $param['value'];

				// only build query string based on parameters (ex: categories, tags, authors)
				// that affects the return posts, not the number of posts
				// to exclude things correctly
				// ex: category: 10, count: 7 is similar to category: 10, count: 100
				// in terms of query param strings because if they are different, we cannot ignore
				// loaded posts from category: 10 when they only have different count parameter
				if (!in_array($key, array('posts_per_page', 'ignore_loaded_posts'))) {
					$query_param_string .= $key . ':' . $val;
				}

				// update expecting count
				if ('posts_per_page' === $key && is_numeric($val)) {
					$count = (int) $val;
				}

				// special keys
				if ('ignore_loaded_posts' === $key) {
					$ignore_loaded_posts = 'all' === $param['value'] ? 'all' : 'query';
					// if ($val) {
					//     $args['post__not_in'] = array_merge(...array_values($dragblock_queries));
					// }
					continue;
				}

				// we can use shortcodes for the query parameters
				if (strpos($val, '[dragblock.') !== false) {

					$val = do_shortcode($val);
				}

				// this parameter require an array as its value
				// following the requirements in WP_Query documentation
				if (strpos($key, '__') !== false) {
					$args[$key] = explode(',', $val);
					continue;
				}

				$args[$key] = $val;
			}

			// override post view count order
			if (isset($args['orderby']) && DRAGBLOCK_POST_VIEWS_KEY === $args['orderby']) {
				$args['meta_key'] = DRAGBLOCK_POST_VIEWS_KEY;
				$args['orderby'] = 'meta_value_num';
			}

			// if ($ignore_loaded_posts && isset($dragblock_loaded_posts[$query_param_string])) {
			// 	$args['post__not_in'] = $dragblock_loaded_posts[$query_param_string];
			// }

			if ($ignore_loaded_posts) {
				$ignore_posts = array();
				if ('all' === $ignore_loaded_posts) {
					foreach ($dragblock_loaded_posts as $post_ids) {
						if (!is_array($post_ids)) continue;
						$ignore_posts = array_merge($ignore_posts, $post_ids);
					}
				} else if (isset($dragblock_loaded_posts[$query_param_string])) {
					$ignore_posts = $dragblock_loaded_posts[$query_param_string];
				}
				if (count($ignore_posts)) {
					$args['post__not_in'] = $ignore_posts;
				}
			}

			$dragblock_current_query_list_id = $id;

			if ('WP_Query' === $slug) {

				// var_dump(dragblock_wp_query_args_processor($args));
				$post_ids = new WP_Query(dragblock_wp_query_args_processor($args));

				$post_ids = $post_ids->posts;
				// if (isset($_GET['content']) && $_GET['content'] != '') {
				// 	var_dump($post_ids);
				// }
				// update loaded posts if post_per_page is set
				if ($count > 0) {
					if (!isset($dragblock_loaded_posts[$query_param_string])) {
						$dragblock_loaded_posts[$query_param_string] = array();
					}
					// we don't need to check count here because we set post_per_page
					// and wp_query will return exactly or lower that number of posts						
					foreach ($post_ids as $post_id) {
						if (in_array($post_id, $dragblock_loaded_posts[$query_param_string])) {
							continue;
						}
						array_push($dragblock_loaded_posts[$query_param_string], $post_id);
					}
				}
				// if user does not tell exactly post they want to load, the wp_query will load 
				// the number of post equal the default setting, which could larger than the number
				// of posts displayed. So if we add to loaded posts, the next query will not display
				// the extra posts (beyond the displayed posts)
				// so we need to add the query param string then we use the parse item to add the 
				// loaded posts (this is the best we can do but if user uses two similar parse item,
				// the results could be affected)
				else {

					$dragblock_query_param_strings[$dragblock_current_query_list_id] = $query_param_string;
					$dragblock_loaded_posts[$query_param_string] = array();
				}

				$dragblock_queries[$dragblock_current_query_list_id] = $post_ids;


				// always reset the query pointer when query a new query
				$dragblock_current_query_list_item_id = null;
			} elseif ('WP_Query_Default' === $slug) {
				// always reset the query pointer when query a new query
				$dragblock_current_query_list_item_id = null;
				$dragblock_current_query_list_id = 'default';
			}
		}

		// other queries
		if ('parse_item' === $slug) {

			if (!empty($params['query_id'])) {
				$dragblock_current_query_list_id = $params['query_id'];
			}
			if (!empty($params['item_index'])) {
				$dragblock_current_query_list_item_id = intval($params['item_index']);
			} elseif (null === $dragblock_current_query_list_item_id) {
				$dragblock_current_query_list_item_id = 0;
			} else {
				$dragblock_current_query_list_item_id++;
			}

			// if empty parse item, stop render the block
			if (
				!isset($dragblock_queries[$dragblock_current_query_list_id]) ||
				!isset($dragblock_queries[$dragblock_current_query_list_id][$dragblock_current_query_list_item_id])
			) {
				$parsed_block['attrs']['dragBlockRenderability'] = array(
					array(
						'slug' => 'render',
						'value' => 'never',
					)
				);
			}

			// update loaded posts
			else if (isset($dragblock_query_param_strings[$dragblock_current_query_list_id])) {

				$query_param_string = $dragblock_query_param_strings[$dragblock_current_query_list_id];

				array_push($dragblock_loaded_posts[$query_param_string], $dragblock_queries[$dragblock_current_query_list_id][$dragblock_current_query_list_item_id]);
			}
		}
	}

	return $parsed_block;
}

function dragblock_wp_query_args_processor($args)
{
	// Process the tax_query to filter the results for custom taxonomy
	$tax_query = array();
	foreach ($args as $key => $value) {
		// Check if the property starts with DRAGBLOCK_START_TAX_QUERY_KEY
		if (strpos($key, DRAGBLOCK_START_TAX_QUERY_KEY) === 0) {
			// Extract taxonomy name
			$taxonomy_name = str_replace(DRAGBLOCK_START_TAX_QUERY_KEY, '', $key);
			$taxonomy_name = str_replace('__in', '', $taxonomy_name);
			// Add taxonomy query
			$tax_query[] = array(
				'taxonomy' => $taxonomy_name,
				'field'    => 'term_id',
				'terms'    => $value,
			);
			// Remove the taxonomy property from $data
			unset($args[$key]);
		}
	}

	// If tax_query is not empty, add it to $data
	if (!empty($tax_query)) {
		$args['tax_query'] = $tax_query;
	}

	// var_dump($args['tax_query']); die();

	return $args;
}


// add_action('wp_footer', function () {
//     global $dragblock_queries;
//     global $dragblock_current_query_list_id;
//     global $dragblock_current_query_list_item_id;
//     global $dragblock_loaded_posts;

//     // var_dump($dragblock_queries);
//     // var_dump($dragblock_current_query_list_id);
//     // var_dump($dragblock_current_query_list_item_id);
//     var_dump($dragblock_loaded_posts);
// });
