<?php
/**
 * Livada SEO — Module Breadcrumbs
 *
 * Provides a breadcrumb trail as a WordPress shortcode [livada_breadcrumbs]
 * and a global PHP helper livada_seo_breadcrumbs().
 *
 * Inline JSON-LD BreadcrumbList is embedded directly in the nav element.
 * No microdata attributes are added to HTML elements, avoiding duplication
 * with the Schema module's global @graph output.
 *
 * Settings consumed (via Livada_SEO_Loader::get_setting()):
 *   - breadcrumb_home_text  : label for the Home item (default 'Accueil')
 *   - breadcrumb_separator  : separator glyph/entity (default '&raquo;')
 *
 * @package Livada_SEO
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Livada_SEO_Breadcrumbs {

	/**
	 * Whether the shortcode has been rendered on the current request.
	 * Used to conditionally enqueue the stylesheet via wp_footer.
	 *
	 * @var bool
	 */
	private static bool $css_needed = false;

	// ── Bootstrap ─────────────────────────────────────────────────────────────

	/**
	 * Registers the shortcode and the deferred CSS enqueue hook.
	 * Called once by Livada_SEO_Loader on `plugins_loaded`.
	 */
	public static function init(): void {
		add_shortcode( 'livada_breadcrumbs', [ self::class, 'render' ] );

		// Enqueue CSS early when the current post content contains the shortcode.
		add_action( 'wp_enqueue_scripts', [ self::class, 'maybe_enqueue_css_early' ] );

		// Fallback: if CSS was not enqueued early (e.g. shortcode in widget or
		// template function call), enqueue it from wp_footer before output.
		add_action( 'wp_footer', [ self::class, 'maybe_enqueue_css_late' ], 1 );
	}

	// ── CSS enqueue ───────────────────────────────────────────────────────────

	/**
	 * Enqueues breadcrumbs.css when the queried post/page contains the shortcode.
	 * Hooked to wp_enqueue_scripts.
	 */
	public static function maybe_enqueue_css_early(): void {
		global $post;

		if ( $post instanceof WP_Post && has_shortcode( $post->post_content, 'livada_breadcrumbs' ) ) {
			self::enqueue_css();
		}
	}

	/**
	 * Enqueues breadcrumbs.css if render() was called (e.g. via template
	 * function) but the stylesheet was not registered yet.
	 * Hooked to wp_footer at priority 1.
	 */
	public static function maybe_enqueue_css_late(): void {
		if ( self::$css_needed && ! wp_style_is( 'livada-breadcrumbs', 'enqueued' ) ) {
			self::enqueue_css();
		}
	}

	/**
	 * Registers and enqueues the breadcrumbs stylesheet.
	 */
	private static function enqueue_css(): void {
		wp_enqueue_style(
			'livada-breadcrumbs',
			LIVADA_SEO_URL . 'assets/css/breadcrumbs.css',
			[],
			LIVADA_SEO_VERSION
		);
	}

	// ── Rendering ─────────────────────────────────────────────────────────────

	/**
	 * Shortcode callback: [livada_breadcrumbs]
	 * Returns the breadcrumb HTML string (shortcodes must return, not echo).
	 *
	 * @param array<string,mixed>|string $atts  Shortcode attributes (unused).
	 * @param string|null                $content Enclosed content (unused).
	 * @return string
	 */
	public static function render( $atts = [], ?string $content = null ): string {
		// Signal that CSS is needed (fallback path for template function calls).
		self::$css_needed = true;

		$crumbs = self::build_trail();

		if ( empty( $crumbs ) ) {
			return '';
		}

		$separator = Livada_SEO_Loader::get_setting( 'breadcrumb_separator', '&raquo;' );

		// ── JSON-LD ───────────────────────────────────────────────────────────

		$ld_items = [];
		$position = 1;

		foreach ( $crumbs as $crumb ) {
			if ( ! empty( $crumb['url'] ) ) {
				$ld_items[] = [
					'@type'    => 'ListItem',
					'position' => $position,
					'name'     => $crumb['label'],
					'item'     => $crumb['url'],
				];
				$position++;
			}
		}

		$ld_json = json_encode(
			[
				'@context'        => 'https://schema.org',
				'@type'           => 'BreadcrumbList',
				'itemListElement' => $ld_items,
			],
			JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
		);

		// ── HTML ──────────────────────────────────────────────────────────────

		$html  = '<nav class="livada-breadcrumbs" aria-label="Fil d\'ariane">' . "\n";
		$html .= "\t" . '<script type="application/ld+json">' . $ld_json . '</script>' . "\n";
		$html .= "\t<ol>\n";

		$last_index = count( $crumbs ) - 1;

		foreach ( $crumbs as $i => $crumb ) {
			$is_last = ( $i === $last_index );

			// Item.
			if ( $is_last ) {
				$html .= "\t\t<li><span aria-current=\"page\">" . esc_html( $crumb['label'] ) . '</span></li>' . "\n";
			} else {
				$html .= "\t\t<li><a href=\"" . esc_url( $crumb['url'] ) . '">' . esc_html( $crumb['label'] ) . '</a></li>' . "\n";
				$html .= "\t\t<li class=\"separator\" aria-hidden=\"true\">" . $separator . '</li>' . "\n";
			}
		}

		$html .= "\t</ol>\n";
		$html .= '</nav>' . "\n";

		return $html;
	}

	// ── Trail builder ─────────────────────────────────────────────────────────

	/**
	 * Builds the ordered breadcrumb array for the current context.
	 * Each item: [ 'label' => string, 'url' => string|'' ]
	 * The last item carries an empty url (it is the current page, not linked).
	 *
	 * @return array<int,array{label:string,url:string}>
	 */
	private static function build_trail(): array {
		$home_text = (string) Livada_SEO_Loader::get_setting( 'breadcrumb_home_text', 'Accueil' );
		$home_url  = home_url( '/' );

		$trail = [
			[ 'label' => $home_text, 'url' => $home_url ],
		];

		// ── Front page ────────────────────────────────────────────────────────
		if ( is_front_page() ) {
			// Single item: the home item becomes the current page.
			$trail[0]['url'] = '';
			return $trail;
		}

		// ── 404 ───────────────────────────────────────────────────────────────
		if ( is_404() ) {
			$trail[] = [ 'label' => __( 'Page not found', 'livada-seo' ), 'url' => '' ];
			return $trail;
		}

		// ── Search results ────────────────────────────────────────────────────
		if ( is_search() ) {
			$trail[] = [ 'label' => __( 'Search results', 'livada-seo' ), 'url' => '' ];
			return $trail;
		}

		// ── Tag archive ───────────────────────────────────────────────────────
		if ( is_tag() ) {
			$tag = get_queried_object();
			if ( $tag instanceof WP_Term ) {
				$trail[] = [ 'label' => $tag->name, 'url' => '' ];
			}
			return $trail;
		}

		// ── Category archive ──────────────────────────────────────────────────
		if ( is_category() ) {
			$term = get_queried_object();
			if ( $term instanceof WP_Term ) {
				// Walk ancestors (oldest first).
				$ancestors = array_reverse( get_ancestors( $term->term_id, 'category', 'taxonomy' ) );
				foreach ( $ancestors as $ancestor_id ) {
					$ancestor = get_term( $ancestor_id, 'category' );
					if ( $ancestor instanceof WP_Term ) {
						$ancestor_url = get_term_link( $ancestor );
						$trail[]      = [
							'label' => $ancestor->name,
							'url'   => is_string( $ancestor_url ) ? $ancestor_url : '',
						];
					}
				}
				$trail[] = [ 'label' => $term->name, 'url' => '' ];
			}
			return $trail;
		}

		// ── Date / author / post-type archives ────────────────────────────────
		if ( is_date() ) {
			$trail[] = [ 'label' => get_the_date( 'F Y' ), 'url' => '' ];
			return $trail;
		}

		if ( is_author() ) {
			$author = get_queried_object();
			if ( $author instanceof WP_User ) {
				$trail[] = [ 'label' => $author->display_name, 'url' => '' ];
			}
			return $trail;
		}

		if ( is_post_type_archive() ) {
			$label   = post_type_archive_title( '', false );
			$trail[] = [ 'label' => (string) $label, 'url' => '' ];
			return $trail;
		}

		// ── Singular: page ────────────────────────────────────────────────────
		if ( is_page() ) {
			$post = get_queried_object();
			if ( ! ( $post instanceof WP_Post ) ) {
				return $trail;
			}

			// Walk ancestor pages oldest-first.
			$ancestors = array_reverse( get_post_ancestors( $post->ID ) );
			foreach ( $ancestors as $ancestor_id ) {
				$ancestor_post = get_post( $ancestor_id );
				if ( $ancestor_post instanceof WP_Post ) {
					$trail[] = [
						'label' => get_the_title( $ancestor_post ),
						'url'   => get_permalink( $ancestor_post ),
					];
				}
			}

			$trail[] = [ 'label' => get_the_title( $post ), 'url' => '' ];
			return $trail;
		}

		// ── Singular: post (and custom post types) ────────────────────────────
		if ( is_singular() ) {
			$post = get_queried_object();
			if ( ! ( $post instanceof WP_Post ) ) {
				return $trail;
			}

			// Primary category (first assigned category).
			$categories = get_the_category( $post->ID );
			if ( ! empty( $categories ) ) {
				$primary_cat = $categories[0];

				// Category ancestors.
				$cat_ancestors = array_reverse( get_ancestors( $primary_cat->term_id, 'category', 'taxonomy' ) );
				foreach ( $cat_ancestors as $ancestor_id ) {
					$ancestor = get_term( $ancestor_id, 'category' );
					if ( $ancestor instanceof WP_Term ) {
						$ancestor_url = get_term_link( $ancestor );
						$trail[]      = [
							'label' => $ancestor->name,
							'url'   => is_string( $ancestor_url ) ? $ancestor_url : '',
						];
					}
				}

				$cat_url = get_term_link( $primary_cat );
				$trail[] = [
					'label' => $primary_cat->name,
					'url'   => is_string( $cat_url ) ? $cat_url : '',
				];
			}

			$trail[] = [ 'label' => get_the_title( $post ), 'url' => '' ];
			return $trail;
		}

		return $trail;
	}
}

// ── Global template function ───────────────────────────────────────────────────

if ( ! function_exists( 'livada_seo_breadcrumbs' ) ) {
	/**
	 * Echoes the breadcrumb trail for use directly in PHP templates.
	 *
	 * Usage:
	 *   <?php livada_seo_breadcrumbs(); ?>
	 */
	function livada_seo_breadcrumbs(): void {
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo Livada_SEO_Breadcrumbs::render();
	}
}
