<?php
if ( ! class_exists( 'NISHIKI_PRO_TOC' ) ) {
	/**
	 * 目次
	 */
	class NISHIKI_PRO_TOC {
		/**
		 * Construct.
		 */
		public function __construct() {
			add_filter( 'the_content', array( $this, 'add_toc_anchor' ) );
			add_action( 'nishiki_pro_toc_fixed_list', array( $this, 'add_toc_fixed_content' ) );
		}

		/**
		 * Create TOC
		 *
		 * @param string $content 本文
		 * @return array
		 */
		public function generate_toc( $content ) {
			$outline               = '';
			$loop                  = 1;
			$exclude               = 0;
			$match_exclude_heading = 0;
			$toc_title_text        = esc_html( get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_title_text', __( 'Table Of Contents', 'nishiki-pro' ) ) );
			$title                 = '';
			$anchor_array          = array();
			$max_level             = 2;
			$min_level             = absint( get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_min_level', '3' ) );
			$level_array           = array_fill( 1, 6, 0 );
			$level_number          = absint( get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_level_number', '4' ) );

			// Get Content heading.
			// h2 + h3 h[2-3]
			// h2 only h[2]
//			if ( preg_match_all( '/<h([' . $max_level . '-' . $min_level . '])(.*?)>(.*?)<\/h\1>/', $content, $matches, PREG_SET_ORDER ) ) {
			if ( preg_match_all( '/<h([' . $max_level . '-' . $min_level . '])([^>]*class="[^"]*wp-block-heading[^"]*"[^>]*)>(.*?)<\/h\1>(?![^<]*<\/h[' . $max_level . '-' . $min_level . ']>)/', $content, $matches, PREG_SET_ORDER ) ) {
				// var_dump($matches);
				// var_dump(count($matches));

				// Get the largest heading level matched headings.
				$match_max_level = intval(
					min(
						array_map(
							function( $m ) {
								return $m[1];
							},
							$matches
						)
					)
				);

				// Current level.
				$current_level = $match_max_level - 1;

				// 除外数
				$match_exclude_heading = array_sum(
					array_map(
						function( $m ) {
							if ( strpos( $m[2], 'post-title' ) !== false ) {
								return 1;
							}
						},
						$matches
					)
				);

				// 表示合計
				$show_match = count( $matches ) - $match_exclude_heading;

				$flag = false;

				// Match level count and find $max_level.
				// if ( count( $matches ) >= $level_number && $match_max_level == $max_level ) {

				if ( $show_match >= $level_number && $match_max_level === $max_level ) {
					foreach ( $matches as $m ) {
						$level      = intval( $m[1] );  // level number.
						$attributes = $m[2];  // level attribute.
						$text       = strip_shortcodes( $m[3] );  // level text.

						// クラスに「post-title」があれば処理をスキップ
						if ( strpos( $attributes, 'post-title' ) !== false ) {
							continue;
						}

						// When $max_level appears in the heading of the loop.
						if ( $level === $max_level ) {
							$flag = true;
						}

						if ( true === $flag ) {

							// ex. h3 > h2
							while ( $current_level > $level ) {
								--$current_level;
								$outline .= '</li></ul>';
							}

							// ex. h3 == h3
							if ( $current_level === $level ) {
								$outline .= '</li><li>';
							} else {
								while ( $current_level < $level ) {
									++$current_level;
									$outline .= sprintf( '<ul class="indent-h%s"><li>', $current_level );
								}

								$level_array_count = count( $level_array );
								for ( $idx = $current_level + 0; $idx < $level_array_count; ++$idx ) {
									$level_array[ $idx ] = 0;
								}
							}

							// Update the number of level.
							++$level_array[ $current_level ];

							// Generate path.
							$level_fullpath = array();
							for ( $idx = $match_max_level; $idx <= $level; ++$idx ) {
								$level_fullpath[] = $level_array[ $idx ];
							}

							// Anchor.

							// idの値のみ取得
							$attributes_id = preg_match_all( '/id="([^"]*)"/', $attributes, $matches_id, PREG_SET_ORDER );

							// $target_anchor = 'chapter-' . implode( '-', $level_fullpath );

							if ( $attributes_id ) {
								$target_anchor = $matches_id[0][1];
							} else {
								$target_anchor = 'chapter-' . implode( '-', $level_fullpath );
							}

							// Anchor html.
							if ( 0 === $level_fullpath[0] ) {
								++$exclude;
								$outline .= sprintf( '<a class="toc-link" href="#%s" data-nishiki-pro-scroll>%s</a>', esc_attr( $target_anchor ), $text );
							} else {
								$outline .= sprintf( '<a class="toc-link" href="#%s" data-nishiki-pro-scroll>%s</a>', esc_attr( $target_anchor ), $text );
							}

							$anchor_array[] = $target_anchor;

							++$loop;

						} else {
							++$exclude;
							$anchor_array[] = '';
						}
					}

					// var_dump($anchor_array);

					// Close tags.
					while ( $current_level >= $match_max_level ) {
						$outline .= '</li></ul>';
						--$current_level;
					}
				}

				if ( $show_match >= $level_number ) {
					$title = $toc_title_text;
					// $outline = '<div class="nishiki-pro-toc"><p class="title"><i class="icomoon icon-list2"></i>' . $toc_title_text . '</p>' . $outline . '</div>';
				}

				// Replace content anchor.
				// chapter 付きの見出しに置換する
				if ( ! empty( $anchor_array ) ) {
					$content = preg_replace_callback(
//						'/<h([' . $max_level . '-' . $min_level . '])(.*?)>/',
						'/<h([' . $max_level . '-' . $min_level . '])([^>]*class="[^"]*wp-block-heading[^"]*"[^>]*)>/',
						function ( $matches ) use ( &$count, $anchor_array, $exclude ) {
							$attributes = $matches[2];

							// クラスに「post-title」があれば処理をスキップ
							if ( strpos( $attributes, 'post-title' ) !== false ) {
								return '<h' . $matches[1] . $matches[2] . '>';
							}

							$count++;

							if ( $count <= $exclude ) {
								return '<h' . $matches[1] . $matches[2] . '>';
							} else {
								// idをつける
								return '<h' . $matches[1] . $matches[2] . ' id="' . $anchor_array[ $count - 1 ] . '" data-nishiki-pro-toc-anchor>';
							}
						},
						$content
					);
				}

				// Generate outline.
				if ( $show_match >= $level_number && get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_display', true ) && empty( get_post_meta( get_the_ID(), '_nishiki_pro_toc_disable_' . get_post_type(), true ) ) ) {

					$toc_content_title = '<p class="title"><i class="icomoon icon-list2"></i>' . $title . '</p><input id="nishiki-pro-toc-close-toggle" type="checkbox" checked><label class="close" id="nishiki-pro-toc-close-button" aria-label="close" for="nishiki-pro-toc-close-toggle"><span class="slider"></span></label>';

					// Insert $outline before first $max_level.
//					if ( preg_match_all( '/<h([2])(?:.*?)>(.*?)<\/h\1>/', $content, $matches_h, PREG_SET_ORDER ) ) {
					if ( preg_match_all( '/<(\w+)[^>]*\bdata-nishiki-pro-toc-anchor\b[^>]*>(.*?)<\/\1>/', $content, $matches_h, PREG_SET_ORDER ) ) {
//					if( preg_match_all( '/(<[^>]+data-nishiki-pro-toc-anchor[^>]*>)/', $content, $matches_h ) ){ //タグだけ取得するにはこっち
						// data-nishiki-pro-toc-anchor が初めに現れる見出しの後に目次挿入
						if ( $matches_h[0][0] ) {
							$content = str_replace( $matches_h[0][0], '<section id="nishiki-pro-toc-content"><div class="nishiki-pro-toc">' . $toc_content_title . $outline . '</div></section>' . $matches_h[0][0], $content );
						}
					}
				}

			}

			return array(
				'content' => $content,
				'title'   => $title,
				'outline' => $outline,
			);
		}

		/**
		 * Add anchor.
		 *
		 * @param string $content 本文
		 * @return $content
		 */
		public function add_toc_anchor( $content ) {
			// Add post and page(exclude front page).
			if ( ! is_singular() || is_front_page() ) {
				return $content;
			}

			// Get toc.
			$toc     = $this->generate_toc( $content );

			$content = $toc['content'];

			return $content;
		}

		/**
		 * Add TOC Fixed List.
		 *
		 * @return void
		 */
		public function add_toc_fixed_content() {
			// Add post and page(exclude front page).
			if ( is_singular() || ! is_front_page() ) {
				$content = get_post_field( 'post_content', get_the_ID() );
				$toc     = $this->generate_toc( $content );
				$title   = $toc['title'];
				$outline = strip_shortcodes( $toc['outline'] );
				
				$class   = [];

				if ( get_theme_mod( 'setting_header_button_design_pattern', '02' ) ) {
					$class[] = 'nishiki-pro-header-button-style';
					$class[] = 'nishiki-pro-header-button-style-' . get_theme_mod( 'setting_header_button_design_pattern', '02' );
				}

				if ( '' !== $outline ) {
					?>
					<div id="nishiki-toc-fixed"<?php echo 'class="' . esc_attr( implode( ' ', $class ) ) . '"'; ?>>
						<div id="toc-fixed-nav">
							<div class="container">
								<div id="toc-current"></div>
								<button id="toc-fixed-button" aria-label="table of contents" class="icon">
									<i class="icomoon icon-list2"></i>
								</button>
							</div>
						</div>
					</div>
					<?php
					$toc_fixed_overlay_class = 'overlay flex fixed w-full h-full';
					if ( get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_fixed_overlay_open_type', 'panel-slide' ) ) {
						$toc_fixed_overlay_class .= ' ' . get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_fixed_overlay_open_type', 'panel-slide' );
					}
					if ( get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_fixed_overlay_backdrop_blur' ) ) {
						$toc_fixed_overlay_class .= ' ' . get_theme_mod( 'setting_' . NISHIKI_PRO_PREFIX_TOC . '_fixed_overlay_backdrop_blur' );
					}
					?>
					<div id="toc-fixed-overlay" class="<?php echo esc_html( $toc_fixed_overlay_class ); ?>">
						<div class="overlay-inner relative w-full container">
							<section id="toc-fixed-list" class="nishiki-pro-toc">
								<p class="title"><i class="icomoon icon-list2"></i><?php echo wp_kses_post( $title ); ?></p>
								<?php echo wp_kses_post( $outline ); ?>
							</section>
							<button id="close-panel-button-toc" class="close" aria-label="<?php esc_html_e( 'close', 'nishiki-pro' ); ?>"><i class="icomoon icon-close"></i></button>
						</div>
					</div>
					<?php
				}
			}
		}
	}

	$output = new NISHIKI_PRO_TOC();
}

if ( ! function_exists( 'nishiki_pro_toc_disable_add_meta_box' ) ) {
	add_action( 'add_meta_boxes', 'nishiki_pro_toc_disable_add_meta_box' );
	/**
	 * Adds a box to the main column on the Post and Page edit screens.
	 *
	 * @return void
	 */
	function nishiki_pro_toc_disable_add_meta_box() {

		$screens = nishiki_pro_get_all_post_types();
		foreach ( $screens as $screen ) {
			add_meta_box(
				'nishiki_pro_toc_disable_' . $screen,
				__( '目次を非表示にする', 'nishiki_pro' ),
				'nishiki_pro_toc_meta_box_disable_callback',
				$screen,
				'side'
			);
		}
	}
}

if ( ! function_exists( 'nishiki_pro_toc_meta_box_disable_callback' ) ) {
	/**
	 * Prints the box content.
	 *
	 * @param WP_Post $post The object for the current post/page.
	 */
	function nishiki_pro_toc_meta_box_disable_callback( $post ) {

		// Add a nonce field so we can check for it later.
		wp_nonce_field( 'nishiki_pro_toc_disable_save_meta_box_data', 'nishiki_pro_toc_disable_meta_box_nonce' );

		/*
		 * Use get_post_meta() to retrieve an existing value
		 * from the database and use the value for the form.
		 */
		$value = get_post_meta( $post->ID, '_nishiki_pro_toc_disable_' . get_post_type(), true );

		$checked = ( $value ) ? ' checked="checked"' : '';

		echo '<label for="nishiki_pro_toc"><input type="checkbox" id="nishiki_pro_toc" name="nishiki_pro_toc_disable_new_field" value="1" ' . esc_attr( $checked ) . ' /> 非表示</label>';
	}
}

if ( ! function_exists( 'nishiki_pro_toc_disable_save_meta_box_data' ) ) {
	add_action( 'save_post', 'nishiki_pro_toc_disable_save_meta_box_data' );

	/**
	 * When the post is saved, saves our custom data.
	 *
	 * @param int $post_id The ID of the post being saved.
	 */
	function nishiki_pro_toc_disable_save_meta_box_data( $post_id ) {

		// Check if our nonce is set.
		if ( ! isset( $_POST['nishiki_pro_toc_disable_meta_box_nonce'] ) ) {
			return;
		}

		// Verify that the nonce is valid.
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nishiki_pro_toc_disable_meta_box_nonce'] ) ), 'nishiki_pro_toc_disable_save_meta_box_data' ) ) {
			return;
		}

		// If this is an autosave, our form has not been submitted, so we don't want to do anything.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}

		// Check the user's permissions.
		if ( isset( $_POST['post_type'] ) && 'page' === $_POST['post_type'] ) {

			if ( ! current_user_can( 'edit_page', $post_id ) ) {
				return;
			}
		} else {

			if ( ! current_user_can( 'edit_post', $post_id ) ) {
				return;
			}
		}

		/* OK, it's safe for us to save the data now. */

		$value = get_post_meta( $post_id, '_nishiki_pro_toc_disable_' . get_post_type(), true );

		// 値がポストされていなかったら
		if ( ! isset( $_POST['nishiki_pro_toc_disable_new_field'] ) ) {
			if ( $value ) {
				delete_post_meta( $post_id, '_nishiki_pro_toc_disable_' . get_post_type(), 1 );
			}
			return;
		} else {
			// Sanitize user input.
			$my_data = sanitize_text_field( wp_unslash( $_POST['nishiki_pro_toc_disable_new_field'] ) );

			// Update the meta field in the database.
			update_post_meta( $post_id, '_nishiki_pro_toc_disable_' . get_post_type(), $my_data );
		}
	}
}
