<?php
namespace KsPortfolio;

/**
 * Class Breadcrumbs
 *
 * This class is responsible for generating and managing breadcrumb navigation
 * for the WordPress theme. Breadcrumbs provide a navigational aid that helps
 * users understand their location within the website's hierarchy.
 *
 * @package Basic-WP
 * @subpackage Breadcrumbs
 */
class Breadcrumbs {
	/**
	 * Generates the breadcrumb navigation for the website.
	 *
	 * This method is responsible for creating and returning the breadcrumb
	 * trail, which helps users navigate the website by showing their current
	 * location within the site's hierarchy.
	 *
	 * @return array An array of breadcrumb items, where each item is typically an
	 *               associative array containing 'title' and 'url' keys.
	 */
	public static function generate() {
		global $post;

		$breadcrumbs = array();

		// Always start with Home
		$breadcrumbs[] = self::getHomeBreadcrumb();

		if ( is_front_page() ) {
			// Front Page - do nothing
			return $breadcrumbs;
		} elseif ( is_home() ) {
			// Blog Index - add the Blog Posts Index page title
			$breadcrumbs[] = self::getBlogPostsIndexBreadcrumb();
		} elseif ( is_singular( 'post' ) ) {
			// Single Post - add the category and post title
			$breadcrumbs = array_merge( $breadcrumbs, self::getSinglePostBreadcrumbs() );
		} elseif ( is_singular() && ! is_page() ) {
			// Single Custom Post Type - add the post type archive and post title
			$breadcrumbs = array_merge( $breadcrumbs, self::getCustomPostTypeBreadcrumbs() );
		} elseif ( is_page() ) {
			// Static Page - add the parent pages if any, and the page title
			$breadcrumbs = array_merge( $breadcrumbs, self::getStaticPageBreadcrumbs( $post ) );
		} elseif ( is_category() || is_tag() || is_tax() ) {
			// Taxonomy Archive - if this is a project-type term, surface the
			// Projects archive as a clickable parent in the trail.
			if ( is_tax( 'project-type' ) ) {
				$breadcrumbs[] = self::getProjectsArchiveLinkBreadcrumb();
			}
			$breadcrumbs[] = self::getTaxonomyArchiveBreadcrumb();
		} elseif ( is_post_type_archive() ) {
			// Post Type Archive - add the post type name
			$breadcrumbs[] = self::getPostTypeArchiveBreadcrumb();
		} elseif ( is_day() ) {
			// Daily Archive - add the month and day links
			$breadcrumbs = array_merge( $breadcrumbs, self::getDateArchiveBreadcrumbs() );
		} elseif ( is_month() ) {
			// Monthly Archive - add the month link
			$breadcrumbs[] = self::getMonthArchiveBreadcrumb();
		} elseif ( is_year() ) {
			// Yearly Archive - add the year link
			$breadcrumbs[] = self::getYearArchiveBreadcrumb();
		} elseif ( is_author() ) {
			// Author Archive - add the author name
			$breadcrumbs[] = self::getAuthorArchiveBreadcrumb();
		} elseif ( is_search() ) {
			// Search Results - add the search query
			$breadcrumbs[] = self::getSearchBreadcrumb();
		} elseif ( is_404() ) {
			// 404 Not Found - add a 404 message
			$breadcrumbs[] = self::get404Breadcrumb();
		}

		return $breadcrumbs;
	}

	/** Generates the breadcrumb for the home page.
	 *
	 * This method is responsible for creating the breadcrumb
	 * link or label that represents the home page in the breadcrumb
	 * navigation trail.
	 *
	 * @return string The HTML or text representation of the home breadcrumb.
	 */
	private static function getHomeBreadcrumb() {
		return array(
			'url'   => home_url(),
			'label' => 'Home',
		);
	}

	/** Generates the breadcrumb for the blog posts index page.
	 *
	 * This method is responsible for creating a breadcrumb entry
	 * that represents the blog posts index page in the breadcrumb trail.
	 *
	 * @return array An associative array representing the breadcrumb for the blog posts index page.
	 */
	private static function getBlogPostsIndexBreadcrumb() {
		return array( 'label' => get_the_title( get_option( 'page_for_posts' ) ) );
	}

	/** Generates the breadcrumb trail for a single post.
	 *
	 * This method is responsible for creating the breadcrumb navigation
	 * specific to single post views. It typically includes links to the
	 * homepage, category (or categories) the post belongs to, and the
	 * post title itself.
	 *
	 * @return array An array representing the breadcrumb trail, where each
	 *               element is a breadcrumb item (e.g., URL and label).
	 */
	private static function getSinglePostBreadcrumbs() {
		$breadcrumbs = array();
		$categories  = get_the_category();

		$breadcrumbs[] = array(
			'url'   => get_permalink( get_option( 'page_for_posts' ) ),
			'label' => get_the_title( get_option( 'page_for_posts' ) ),
		);

		if ( ! empty( $categories ) ) {
			$cat           = $categories[0];
			$breadcrumbs[] = array(
				'url'   => get_category_link( $cat ),
				'label' => $cat->name,
			);
		}

		$breadcrumbs[] = array( 'label' => get_the_title() );
		return $breadcrumbs;
	}

	/** Generates breadcrumbs for custom post types.
	 *
	 * This method is responsible for creating breadcrumb navigation
	 * specific to custom post types. It retrieves and formats the
	 * breadcrumb trail based on the custom post type's hierarchy
	 * and structure.
	 *
	 * @return array An array representing the breadcrumb trail for the custom post type.
	 */
	private static function getCustomPostTypeBreadcrumbs() {
		$breadcrumbs = array();
		$postType    = get_post_type_object( get_post_type() );
		if ( $postType && ! in_array( get_post_type(), array( 'post', 'page' ), true ) ) {
			$breadcrumbs[] = array(
				'url'   => get_post_type_archive_link( $postType->name ),
				'label' => $postType->labels->name,
			);
		}
		$breadcrumbs[] = array( 'label' => get_the_title() );
		return $breadcrumbs;
	}

	/** Generates breadcrumbs for a static page.
	 *
	 * This method is responsible for creating breadcrumb navigation
	 * for static pages in a WordPress theme. It utilizes the provided
	 * post object to determine the breadcrumb structure.
	 *
	 * @param WP_Post $post The WordPress post object representing the static page.
	 * @return array An array of breadcrumb items, where each item is typically
	 *               an associative array containing 'title' and 'url' keys.
	 */
	private static function getStaticPageBreadcrumbs( $post ) {
		$breadcrumbs = array();
		if ( $post->post_parent ) {
			$ancestors = array_reverse( get_post_ancestors( $post->ID ) );
			foreach ( $ancestors as $ancestor ) {
				$breadcrumbs[] = array(
					'url'   => get_permalink( $ancestor ),
					'label' => get_the_title( $ancestor ),
				);
			}
		}
		$breadcrumbs[] = array( 'label' => get_the_title() );
		return $breadcrumbs;
	}

	/** Generates a breadcrumb for taxonomy archive pages.
	 *
	 * This method is responsible for creating breadcrumb navigation
	 * specific to taxonomy archive pages, providing users with a clear
	 * path to navigate back to the taxonomy or related sections.
	 *
	 * @return array An array representing the breadcrumb trail for the taxonomy archive.
	 */
	private static function getTaxonomyArchiveBreadcrumb() {
		$term = get_queried_object();
		return $term && isset( $term->name ) ? array( 'label' => $term->name ) : array();
	}

	/** Generates a breadcrumb for the archive page of a custom post type.
	 *
	 * This method is responsible for creating a breadcrumb link that points
	 * to the archive page of a specific custom post type. It is typically used
	 * in breadcrumb navigation to provide users with a way to navigate back
	 * to the archive page of the post type they are currently viewing.
	 *
	 * @return array An array containing the breadcrumb data for the custom post type archive.
	 */
	private static function getPostTypeArchiveBreadcrumb() {
		$postType = get_post_type_object( get_post_type() );
		return $postType ? array( 'label' => $postType->labels->name ) : array();
	}

	/** Generates a clickable Projects archive breadcrumb.
	 *
	 * Used in the taxonomy archive trail so users have a working "back to
	 * all projects" link in the breadcrumb. Distinct from
	 * getPostTypeArchiveBreadcrumb(), which omits the URL because on the
	 * post-type archive itself that crumb is the active leaf and shouldn't
	 * link to itself.
	 *
	 * @return array Breadcrumb data with both label and url.
	 */
	private static function getProjectsArchiveLinkBreadcrumb() {
		$url = get_post_type_archive_link( 'projects' );
		return array(
			'url'   => $url ? $url : '',
			'label' => __( 'Projects', 'ks-portfolio' ),
		);
	}

	/** Generates breadcrumbs for date-based archives.
	 *
	 * This method is responsible for creating breadcrumb navigation
	 * for WordPress date archive pages, such as year, month, or day archives.
	 *
	 * @return array An array representing the breadcrumb trail for the date archive.
	 */
	private static function getDateArchiveBreadcrumbs() {
		return array(
			array(
				'url'   => get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) ),
				'label' => get_the_date( 'F Y' ),
			),
			array( 'label' => get_the_date() ),
		);
	}

	/** Generates a breadcrumb for a monthly archive page.
	 *
	 * This method is responsible for creating a breadcrumb
	 * specific to WordPress monthly archive pages. It typically
	 * includes the year and month as part of the breadcrumb trail.
	 *
	 * @return string The HTML markup for the monthly archive breadcrumb.
	 */
	private static function getMonthArchiveBreadcrumb() {
		return array( 'label' => get_the_date( 'F Y' ) );
	}

	/** Generates a breadcrumb for the year-based archive page.
	 *
	 * This method is responsible for creating a breadcrumb link
	 * specific to the year archive in a WordPress site. It is typically
	 * used to provide navigation for users when they are viewing posts
	 * filtered by a specific year.
	 *
	 * @return string The HTML markup for the year archive breadcrumb.
	 */
	private static function getYearArchiveBreadcrumb() {
		return array( 'label' => get_the_date( 'Y' ) );
	}

	/** Generates the breadcrumb for the author archive page.
	 *
	 * This method is responsible for creating a breadcrumb trail
	 * specific to the author archive, providing navigation context
	 * for pages that display posts by a particular author.
	 *
	 * @return string The HTML markup for the author archive breadcrumb.
	 */
	private static function getAuthorArchiveBreadcrumb() {
		$author = get_queried_object();
		return array( 'label' => 'Author: ' . $author->display_name );
	}

	/** Generates the breadcrumb for search results.
	 *
	 * This method is responsible for creating a breadcrumb trail
	 * specific to search result pages. It helps users navigate back
	 * to the search context or other parts of the site.
	 *
	 * @return string The HTML markup for the search breadcrumb.
	 */
	private static function getSearchBreadcrumb() {
		return array( 'label' => 'Search: ' . get_search_query() );
	}

	/** Generates the breadcrumb trail for a 404 error page.
	 *
	 * This method is responsible for creating a breadcrumb structure
	 * specifically for 404 error pages, providing users with a navigational
	 * context when a requested page is not found.
	 *
	 * @return array An array representing the breadcrumb trail for the 404 page.
	 */
	private static function get404Breadcrumb() {
		return array( 'label' => '404 Not Found' );
	}

	/** Renders the breadcrumb navigation.
	 *
	 * This method generates and outputs the breadcrumb trail for the current page.
	 *
	 * @return void
	 */
	public static function render() {
		$items = self::generate();

		$metadata = array(
			'@context'        => 'https://schema.org',
			'@type'           => 'BreadcrumbList',
			'itemListElement' => array(),
		);

		ob_start();
		?>

		<nav aria-label="Breadcrumbs" class="flex items-center py-2 -mx-2 leading-none" vocab="https://schema.org/" typeof="BreadcrumbList">
			<?php foreach ( $items as $index => $item ) : ?>
				<?php
				$ldItem = array(
					'@type'    => 'ListItem',
					'position' => $index + 1,
					'name'     => htmlspecialchars( $item['label'], ENT_QUOTES, 'UTF-8' ),
				);

				$isActive    = ( $index === count( $items ) - 1 );
				$activeClass = $isActive ? ' active' : '';
				?>
			<span class="p-2 breadcrumb-item<?php echo esc_attr( $activeClass ); ?>"
				<?php
				if ( $isActive ) :
					?>
				aria-current="page"<?php endif; ?>>
				<?php if ( ! empty( $item['url'] ) ) : ?>
				<a href="<?php echo esc_url( $item['url'] ); ?>">
					<?php if ( $index === 0 ) : ?>
					<svg class="flex-shrink-0 w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" aria-label="Home">
                        <path d="M10.707 2.293a1 1 0 00-1.414 0l-7 7a1 1 0 001.414 1.414L4 10.414V17a1 1 0 001 1h2a1 1 0 001-1v-2a1 1 0 011-1h2a1 1 0 011 1v2a1 1 0 001 1h2a1 1 0 001-1v-6.586l.293.293a1 1 0 001.414-1.414l-7-7z" />
					</svg>
					<span class="sr-only"><?php echo esc_attr( $item['label'] ); ?></span>
				<?php else : ?>
					<?php echo esc_attr( $item['label'] ); ?>
				<?php endif; ?>
				</a>
					<?php $ldItem['item'] = $item['url']; ?>
				<?php else : ?>
					<?php echo esc_attr( $item['label'] ); ?>
				<?php endif; ?>
			</span>

				<?php $metadata['itemListElement'][] = $ldItem; ?>

				<?php if ( ! $isActive ) : ?>
				<svg class="flex-shrink-0 w-5 h-5 text-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                    <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
				</svg>
			<?php endif; ?>
			<?php endforeach; ?>
		</nav>

		<script type="application/ld+json"><?php echo esc_js( wp_json_encode( $metadata ) ); ?></script>

		<?php
		echo wp_kses(
			ob_get_clean(),
			array(
				'a'      => array(
					'class'        => array(),
					'href'         => array(),
					'title'        => array(),
					'rel'          => array(),
					'target'       => array(),
					'aria-label'   => array(),
					'aria-current' => array(),
				),
				'nav'    => array(
					'aria-label' => array(),
					'class'      => array(),
					'vocab'      => array(),
					'typeof'     => array(),
				),
				'span'   => array(
					'class'        => array(),
					'aria-current' => array(),
				),
				'svg'    => array(
					'class'       => array(),
					'xmlns'       => array(),
					'viewBox'     => array(),
					'fill'        => array(),
					'aria-hidden' => array(),
					'aria-label'  => array(),
				),
				'path'   => array(
					'd'           => array(),
					'fill-rule'   => array(),
					'clip-rule'   => array(),
					'fill'        => array(),
					'xmlns:xlink' => array(),
				),
				'script' => array(
					'type' => array(),
					'src'  => array(),
				),
			)
		);
	}
}
