<?php
namespace hakoniwa\blocks\ssr\filterSearchTerms;

use hakoniwa\blocks\init\Define;
use hakoniwa\blocks\util\Misc;

class Register {

	/**
	 * Construct.
	 */
	public function __construct() {

		add_action( 'init', [ $this, 'register_dynamic_block' ] );

		// クエリー追加
		add_filter( 'query_vars', [ $this, 'add_query_vars' ] );

		// 検索結果フィルター
		add_action( 'pre_get_posts', [ $this, 'search_filter' ] );

		// クエリーセット
		add_action( 'parse_query', [ $this, 'set_query' ] );
		
	}

	/**
	 * クエリーセット
	 *
	 */
	public function set_query( $query ){
		if ( isset( $_GET[ Define::value( 'plugin_func_name' ) . '_filter_search' ] ) ) {
			$query->is_home = false;
			$query->is_search = true;
		}
	}

	/**
	 * 検索結果フィルター
	 *
	 * @param [type] $query クエリー
	 * @return void
	 */
	public function search_filter( $query ) {
		if ( ! is_admin() && $query->is_main_query() ) {
			if ( $query->is_search ) {

				$taxonomies = Misc::get_taxonomies();

				$form_input_types = [ 'checkbox', 'radio', 'select' ];

				foreach ( $taxonomies as $taxonomy ) {
					if( $taxonomy->show_in_rest ){
						foreach( $form_input_types as $form_input_type ){
							$name = Define::value( 'plugin_func_name' ) . '_' . $form_input_type . '_' . $taxonomy->name;
							if( ! empty( $query->query[ $name ] ) ){
								if( is_array( $query->query[ $name ] ) ){
									foreach( $query->query[ $name ] as $term_id ){
										$tax_query[] = self::create_tax_query( $term_id, $taxonomy->name );
									}
								} else {
									$tax_query[] = self::create_tax_query( $query->query[ $name ], $taxonomy->name );
								}
							}
						}
					}
				}

				// relation
				if( get_query_var( 'relation' ) ){
					$tax_query['relation'] = get_query_var( 'relation' );
				} else {
					$tax_query['relation'] = '';
				}

				// post type
				if( isset( $_GET['post_type'] ) && ! empty( $_GET['post_type'] ) ){

					if( is_array( $_GET['post_type'] ) ){
						$post_types = array_map( 'htmlspecialchars', $_GET['post_type'] );
					}

					if( ! empty( $post_types ) ){
						$query->set( 'post_type', $post_types );
					}

				}

				$query->set( 'tax_query', $tax_query );

				// キーワード or 検索
				if( $tax_query['relation'] === 'or' ){
					add_filter( 'posts_search', [ __CLASS__, 'keyword_posts_search' ], 10, 2 );
					add_filter( 'posts_orderby', [ __CLASS__, 'keyword_search_oderby' ], 10, 2 );
				}

			}
		}
	}

	/**
	 * クエリー追加
	 *
	 * @param array $vars 配列
	 * @return $vars
	 */
	public function add_query_vars( $vars ) {
		$taxonomies = Misc::get_taxonomies();

		foreach ( $taxonomies as $taxonomy ) {
			if( $taxonomy->show_in_rest ){
				$vars[] = Define::value( 'plugin_func_name' ) . '_checkbox_' . $taxonomy->name;
				$vars[] = Define::value( 'plugin_func_name' ) . '_radio_' . $taxonomy->name;
				$vars[] = Define::value( 'plugin_func_name' ) . '_select_' . $taxonomy->name;
			}
		}

		$vars[] = Define::value( 'plugin_func_name' ) . '_filter_search';
		$vars[] = 'relation';

		return $vars;
	}

	/**
	 * tax_query追加
	 */
	public function create_tax_query( $term_id, $taxonomy ){

		$data = [
			'taxonomy' => $taxonomy,
			'field' => 'term_id',
			'terms' => $term_id,
			'operator' => 'IN',
		];

		return $data;
	}

	/**
	 * キーワード検索（or）
	 * 
	 */
	static public function keyword_posts_search( $search, $query ){
		global $wpdb;

		// 検索キーワードを取得
		$search_terms = preg_split( '/[\s　]+/u', $query->get( 's' ), -1, PREG_SPLIT_NO_EMPTY );

		if ( count( $search_terms ) > 1 ) {
			$search_query = [];

			foreach ( $search_terms as $term ) {
				$search_query[] = $wpdb->prepare( "( $wpdb->posts.post_title LIKE %s OR $wpdb->posts.post_content LIKE %s )", '%' . $wpdb->esc_like( $term ) . '%', '%' . $wpdb->esc_like( $term ) . '%' );
			}

			// OR検索用のカスタムSQLを作成
			$search = ' AND (' . implode( ' OR ', $search_query ) . ') ';
		}

		return $search;
	}

	/**
	 * キーワード検索並び順
	 * 
	 */
	static public function keyword_search_oderby( $orderby, $query ) {
		if ( $query->is_search() ) {
			global $wpdb;
			$search_terms = preg_split( '/[\s　]+/u', $query->get( 's' ), -1, PREG_SPLIT_NO_EMPTY );
	
			// 検索スコアを加味した ORDER BY を適用
			$score_parts = [];
			foreach ( $search_terms as $term ) {
				$escaped_term = '%' . $wpdb->esc_like( $term ) . '%';
				$score_parts[] = $wpdb->prepare( "WHEN $wpdb->posts.post_title LIKE %s THEN 3", $escaped_term );
				$score_parts[] = $wpdb->prepare( "WHEN $wpdb->posts.post_content LIKE %s THEN 1", $escaped_term );
			}
	
			if ( ! empty( $score_parts ) ) {
				$orderby = "(CASE " . implode( ' ', $score_parts ) . " ELSE 0 END) DESC, $wpdb->posts.post_date DESC";
			}
		}
	
		return $orderby;
	}

	/**
	 * ダイナミックブロック登録
	 *
	 * @return void
	 */
	public function register_dynamic_block() {

		$args = array(
			'postType'	=> array(
				'type'    => 'string',
				'default' => 'post',
			),
			'displayType'		=> array(
				'type'    => 'string',
				'default' => 'checkbox',
			),
			'selectTaxonomy'	=> array(
				'type'    => 'string',
				'default' => 'category',
			),
			'displayCount'	=> array(
				'type'    => 'boolean',
			),
			'widthDesktop' => array(
				'type'    => 'string',
				'default' => '50',
			),
			'widthTablet'	=> array(
				'type'    => 'string',
				'default' => '50',
			),
			'widthSmartPhone'	=> array(
				'type'    => 'string',
				'default' => '100',
			),
			'term_id'	=> array(
				'type'    => 'string',
				'default' => -1,
			),
			'orderBy'	=> array(
				'type'    => 'string',
				'default' => 'name',
			),
			'order'	=> array(
				'type'    => 'string',
				'default' => 'ASC',
			),
		);

		$taxonomies = Misc::get_taxonomies();

		//　ここにタクソノミーごとのタームを配列で保存しておく
		foreach( $taxonomies as $taxonomy ){
			if( $taxonomy->show_in_rest ){

				$term_ids = '[]';

				$terms = get_terms( 
					array(
						'taxonomy' => $taxonomy->name,
					),
					array(
						'hide_empty' => false,
					)
				);
		
				if( ! empty( $terms ) ){
					$term_ids = json_encode( array_column( $terms, 'term_id' ) );
				}
		
				$args[ 'terms_' . $taxonomy->name ] = array(
					'type'    => 'object',
					'default'  => array(
						'label' => $taxonomy->label,
						'ids' => $term_ids,
					),
				);
			}
		}

		register_block_type(
			Define::value( 'plugin_path' ) . 'build/filter-search-terms',
			array(
				'attributes'      => $args,
				'render_callback' => array( $this, 'block_callback' ),
			)
		);
	}

	/**
	 * レンダリング
	 *
	 * @param array $attributes 属性
	 * @return $card
	 */
	public function block_callback( $attributes, $content, $block ) {

		global $wp_query;
	
			//var_dump($wp_query->query);
	
			//var_dump($attributes[ 'terms_category' ]);
	
			$output  = '';
			$count   = false;
			$orderby = $attributes['orderBy'];
			$order   = $attributes['order'];
			$classes = [];
			$selected_post_type_taxonomies = [];

			$classes[] = 'wp-block-nishiki-blocks-pro-filter-search__item';
	
			if ( ! empty( $attributes['widthDesktop'] ) ) {
				$classes[] = $attributes['widthDesktop'] == '100' ? 'width-100' : 'width-50';
			}
	
			if ( ! empty( $attributes['widthTablet'] ) ) {
				$classes[] = $attributes['widthTablet'] == '100' ? 'md:width-100' : 'md:width-50';
			}
	
			if ( ! empty( $attributes['widthSmartPhone'] ) ) {
				$classes[] = $attributes['widthSmartPhone'] == '100' ? 'sp:width-100' : 'sp:width-50';
			}
	
			$wrapper_attributes = get_block_wrapper_attributes( 
				array( 
					'class' => trim( implode( ' ', $classes ) ),
				)
			);
	
			$output .= '<div ' . wp_kses_post( $wrapper_attributes ) . '>';

			if( ! empty( $attributes[ 'terms_' . $attributes['selectTaxonomy'] ]['label'] ) ){
				$output .= '<p class="label">' . esc_html( $attributes[ 'terms_' . $attributes['selectTaxonomy'] ]['label'] ) . '</p>';
			}
	
			if( ! empty( $attributes['selectTaxonomy'] ) && ! empty( $attributes[ 'terms_' . $attributes['selectTaxonomy'] ] ) ){
				$selected_post_type_taxonomies = get_object_taxonomies( $attributes['postType'] );
	
				if( in_array( $attributes['selectTaxonomy'], $selected_post_type_taxonomies, true ) ){
					$select_terms = json_decode( $attributes[ 'terms_' . $attributes['selectTaxonomy'] ]['ids'] );
				}
			}
	
			if( ! empty( $select_terms ) ){
				if( ! empty( $attributes['displayCount'] ) ) {
					$count = true;
				}

				$output .= '<div class="select-terms">';

				switch( $attributes['displayType'] ){
					case 'checkbox':
						$output .= self::create_checkbox( $select_terms, $attributes['selectTaxonomy'], $count, $orderby, $order );
	
						break;
					
					case 'radio':
						$output .= self::create_radio( $select_terms, $attributes['selectTaxonomy'], $count, $orderby, $order );
		
						break;
					
					case 'select':
						$output .= self::create_selectbox( $select_terms, $attributes['selectTaxonomy'], $count, $orderby, $order );
		
						break;
				}
	
				$output .= '</div>';
			} else {
				if( in_array( $attributes['selectTaxonomy'], $selected_post_type_taxonomies, true ) ){
					$output .= '1 つ以上のタームを選択してください。';
				} else {
					$output .= 'この投稿タイプにはタームが存在しません。他の投稿タイプを選択してください。';
				}
			}
	
			$output .= '</div>';

			return $output;
	}

	/**
	 * チェックボックス作成
	 */
	public function create_checkbox( $terms, $taxonomy, $count, $orderby, $order ){
		$output = '';
		$item_num = '';

		$terms = self::sorted_terms( $terms, $taxonomy, $orderby, $order );
	
		$name = Define::value( 'plugin_func_name' ) . '_checkbox_' . $taxonomy;

		foreach( $terms as $term ){
			// タームデータ取得
			$term_data = get_term( $term, $taxonomy );

			// query の中からタームのデータに合うものを checked する
			global $wp_query;

			$checked = '';

			if( ! is_admin() ){
				foreach( $wp_query->query as $key => $val ){
					if( $key == $name ){
						//var_dump($val);
						if( ! empty( $val ) ){
							if( in_array( strval( $term_data->term_id ), $val, true ) ){
								$checked = ' checked';
							}
						}
					}
				}
			}

			if( $count ){
				$item_num = '(' . $term_data->count . ')';
			}

			$output .= '<label class="checkbox">';
			$output .= '<input type="checkbox" name="' . esc_attr( $name ) . '[]" value="' . absint( $term_data->term_id ) . '"' . esc_attr( $checked ) . '>' . esc_html( $term_data->name . $item_num );
			$output .= '</label>';
		}

		return $output;
	}

	/**
	 * ラジオボタン作成
	 */
	public function create_radio( $terms, $taxonomy, $count, $orderby, $order ){
		$output = '';
		$item_num = '';
		$checked_flag = false;
		$no_checked = '';
		
		$terms = self::sorted_terms( $terms, $taxonomy, $orderby, $order );

		$name = Define::value( 'plugin_func_name' ) . '_radio_' . $taxonomy;

		foreach( $terms as $term ){
			// タームデータ取得
			$term_data = get_term( $term, $taxonomy );

			// query の中からタームのデータに合うものを checked する
			global $wp_query;

			$checked = '';
			
			if( ! is_admin() ){
				foreach( $wp_query->query as $key => $val ){
					if( $key == $name ){
						if( ! empty( $val ) && ! is_array( $val ) ){
							if( strval( $term_data->term_id ) === $val ){
								$checked = ' checked';
								$checked_flag = true;
							}
						}
					}
				}
			}

			if( $count ){
				$item_num = '(' . $term_data->count . ')';
			}

			$output .= '<label class="radio">';
			$output .= '<input type="radio" name="' . esc_attr( $name ) . '" value="' . absint( $term_data->term_id ) . '"' . esc_attr( $checked ) . '>' . esc_html( $term_data->name . $item_num );
			$output .= '</label>';
		}

		if( false === $checked_flag ){
			$no_checked = ' checked';
		}

		$output = '<label class="radio"><input type="radio" name="' . esc_attr( $name ) . '" value=""' . esc_attr( $no_checked ) . '>指定なし</label>' . $output;

		return $output;
	}

	/**
	 * セレクトボックス作成
	 */
	public function create_selectbox( $terms, $taxonomy, $count, $orderby, $order ){
		$output = '';
		$item_num = '';
		$options = '';
		$selected_flag = false;
		$no_selected = '';

		$terms = self::sorted_terms( $terms, $taxonomy, $orderby, $order );

		$name = Define::value( 'plugin_func_name' ) . '_select_' . $taxonomy;

		$output .= '<label class="select">';
		$output .= '<select name="' . esc_attr( $name ) . '">';

		foreach( $terms as $term ){
			// タームデータ取得
			$term_data = get_term( $term, $taxonomy );

			// query の中からタームのデータに合うものを checked する
			global $wp_query;

			$selected = '';
			
			if( ! is_admin() ){
				foreach( $wp_query->query as $key => $val ){
					if( $key == $name ){
						if( ! empty( $val ) && ! is_array( $val ) ){
							if( strval( $term_data->term_id ) === $val ){
								$selected = ' selected';
								$selected_flag = true;
							}
						}
					}
				}
			}

			if( $count ){
				$item_num = '(' . $term_data->count . ')';
			}

			$options .= '<option value="' . absint( $term_data->term_id ) . '"' . esc_attr( $selected ) . '>' . esc_html( $term_data->name . $item_num ) . '</option>';
		}

		if( false === $selected_flag ){
			$no_selected = ' selected';
		}

		$options = '<option value=""' . esc_attr( $no_selected ) . '>指定なし</option>' . $options;

		$output .= $options;
		$output .= '</select>';
		$output .= '</label>';

		return $output;
	}

	/**
	 * ソート条件追加
	 */
	public function sorted_terms( $terms, $taxonomy, $orderby, $order ){

		$sorted_terms = get_terms( [
			'taxonomy'   => $taxonomy,
			'orderby'    => $orderby,
			'order'      => $order,
			'include'    => $terms,
			'hide_empty' => false,
		] );

		return array_column( $sorted_terms, 'term_id' );
	}

}

use hakoniwa\blocks\ssr\filterSearchTerms;
new Register();