<?php
namespace Breadcrumbs;

use WP_PowerSuite\Core\AbstractModule;
use WP_Post;

class Module extends AbstractModule {

	private const MODULE_ID = 'breadcrumbs';

	private const DEFAULT_HOME_TEXT = 'Home';

	/** @var list<string> */
	private const SEPARATORS = [ '›', '/', '>', '→', '»', '|', '·' ];

	/** @var array{separator: string, home_text: string, auto_display: string, post_types: list<string>, post_types_lookup: array<string, true>}|null */
	private ?array $settings_cache = null;

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Breadcrumbs', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return '1.1.1';
	}

	public function getDescription(): string {
		return __( 'Breadcrumb trails on content pages—better orientation for visitors and cleaner site hierarchy for search.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'frontend' ];
	}

	protected function registerHooks(): void {
		if ( is_admin() ) {
			return;
		}

		add_shortcode( 'breadcrumbs', [ $this, 'renderBreadcrumbs' ] );
		add_shortcode( 'wpps_breadcrumbs', [ $this, 'renderBreadcrumbs' ] );

		if ( $this->getSettings()['auto_display'] !== 'none' ) {
			add_filter( 'the_content', [ $this, 'autoInjectBreadcrumbs' ], 12 );
		}
	}

	public function autoInjectBreadcrumbs( string $content ): string {
		if ( ! is_singular() || is_front_page() ) {
			return $content;
		}

		if ( in_the_loop() && ! is_main_query() ) {
			return $content;
		}

		$post_type = get_post_type();
		if ( ! is_string( $post_type ) || ! $this->isEnabledPostType( $post_type ) ) {
			return $content;
		}

		$html = $this->renderBreadcrumbs( [], null, '' );
		if ( $html === '' ) {
			return $content;
		}

		return $this->getSettings()['auto_display'] === 'after'
			? $content . $html
			: $html . $content;
	}

	public function renderBreadcrumbs( $atts = [], ?string $content = null, string $tag = '' ): string {
		unset( $content );

		if ( is_front_page() ) {
			return '';
		}

		$this->enqueueStylesOnce();

		$atts     = is_array( $atts ) ? $atts : [];
		$tag      = $tag !== '' ? $tag : 'breadcrumbs';
		$settings = $this->getSettings();

		$atts = shortcode_atts(
			[
				'separator' => $settings['separator'],
				'home_text' => $this->resolveHomeTextForDisplay( (string) $settings['home_text'] ),
			],
			$atts,
			$tag
		);

		$separator = $this->sanitizeSeparator( (string) $atts['separator'] );
		$home_raw  = sanitize_text_field( (string) $atts['home_text'] );
		$home_text = $home_raw !== ''
			? ( function_exists( 'mb_substr' ) ? mb_substr( $home_raw, 0, 120 ) : substr( $home_raw, 0, 120 ) )
			: $this->resolveHomeTextForDisplay( '' );

		$items   = [];
		$items[] = [
			'url'   => home_url( '/' ),
			'title' => $home_text,
		];

		if ( is_category() ) {
			$cat = get_queried_object();
			if ( $cat instanceof \WP_Term && $cat->taxonomy === 'category' ) {
				if ( (int) $cat->parent > 0 ) {
					$items = array_merge( $items, $this->getCategoryParents( (int) $cat->parent ) );
				}
				$items[] = [
					'url'   => get_category_link( $cat->term_id ),
					'title' => $cat->name,
				];
			}
		} elseif ( is_tag() ) {
			$items[] = [
				'url'   => '',
				'title' => sprintf(
					/* translators: %s: tag name */
					__( 'Tag: %s', 'wp-powersuite' ),
					single_tag_title( '', false )
				),
			];
		} elseif ( is_author() ) {
			$items[] = [
				'url'   => '',
				'title' => sprintf(
					/* translators: %s: author display name */
					__( 'Author: %s', 'wp-powersuite' ),
					get_the_author()
				),
			];
		} elseif ( is_search() ) {
			$items[] = [
				'url'   => '',
				'title' => sprintf(
					/* translators: %s: search query */
					__( 'Search Results for: %s', 'wp-powersuite' ),
					get_search_query()
				),
			];
		} elseif ( is_404() ) {
			$items[] = [
				'url'   => '',
				'title' => __( '404 Not Found', 'wp-powersuite' ),
			];
		} elseif ( is_singular() ) {
			$post = get_queried_object();
			if ( $post instanceof WP_Post ) {
				if ( $post->post_type === 'post' ) {
					$cats = get_the_category( $post->ID );
					if ( ! empty( $cats ) && isset( $cats[0]->term_id ) ) {
						$cat = $cats[0];
						if ( (int) $cat->parent > 0 ) {
							$items = array_merge( $items, $this->getCategoryParents( (int) $cat->parent ) );
						}
						$items[] = [
							'url'   => get_category_link( $cat->term_id ),
							'title' => $cat->name,
						];
					}
				} elseif ( is_post_type_hierarchical( $post->post_type ) && (int) $post->post_parent > 0 ) {
					$items = array_merge( $items, $this->getAncestorPages( (int) $post->post_parent ) );
				}

				$items[] = [
					'url'   => '',
					'title' => get_the_title( $post ),
				];
			}
		}

		if ( count( $items ) <= 1 ) {
			return '';
		}

		return $this->buildBreadcrumbHtml( $items, $separator );
	}

	private function enqueueStylesOnce(): void {
		if ( wp_style_is( 'wpps-breadcrumbs', 'enqueued' ) || wp_style_is( 'wpps-breadcrumbs', 'done' ) ) {
			return;
		}

		$base = defined( 'WP_POWERSUITE_PLUGIN_URL' ) ? WP_POWERSUITE_PLUGIN_URL : '';
		if ( $base === '' ) {
			return;
		}

		wp_enqueue_style(
			'wpps-breadcrumbs',
			$base . 'modules/breadcrumbs/assets/breadcrumbs.css',
			[],
			$this->getVersion()
		);
	}

	private function sanitizeSeparator( string $sep ): string {
		return in_array( $sep, self::SEPARATORS, true ) ? $sep : '›';
	}

	private function buildBreadcrumbHtml( array $items, string $separator ): string {
		$nav_label = esc_attr__( 'Breadcrumb', 'wp-powersuite' );
		$out       = '<nav class="wpps-breadcrumbs" aria-label="' . $nav_label . '">';
		$out      .= '<ol itemscope itemtype="https://schema.org/BreadcrumbList" class="wpps-breadcrumbs__list">';

		$last = count( $items ) - 1;
		foreach ( $items as $index => $crumb ) {
			$title = isset( $crumb['title'] ) ? (string) $crumb['title'] : '';
			$url   = isset( $crumb['url'] ) ? (string) $crumb['url'] : '';
			$pos   = $index + 1;

			$out .= '<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem" class="wpps-breadcrumbs__item">';
			if ( $url !== '' ) {
				$out .= '<a itemprop="item" href="' . esc_url( $url ) . '" class="wpps-breadcrumbs__link">';
				$out .= '<span itemprop="name">' . esc_html( $title ) . '</span></a>';
			} else {
				$out .= '<span itemprop="name" class="wpps-breadcrumbs__current">' . esc_html( $title ) . '</span>';
			}
			$out .= '<meta itemprop="position" content="' . esc_attr( (string) $pos ) . '">';
			if ( $index < $last ) {
				$out .= '<span class="wpps-breadcrumbs__separator" aria-hidden="true">' . esc_html( $separator ) . '</span>';
			}
			$out .= '</li>';
		}

		$out .= '</ol></nav>';

		return $out;
	}

	/** @return list<array{url: string, title: string}> */
	private function getCategoryParents( int $parent_id ): array {
		$out = [];
		while ( $parent_id > 0 ) {
			$cat = get_category( $parent_id );
			if ( ! $cat instanceof \WP_Term || is_wp_error( $cat ) ) {
				break;
			}
			$out[] = [
				'url'   => get_category_link( $cat->term_id ),
				'title' => $cat->name,
			];
			$parent_id = (int) $cat->parent;
		}

		return array_reverse( $out );
	}

	/** @return list<array{url: string, title: string}> */
	private function getAncestorPages( int $parent_id ): array {
		$chain = [];
		$pid   = $parent_id;

		while ( $pid > 0 ) {
			$page = get_post( $pid );
			if ( ! $page instanceof WP_Post ) {
				break;
			}
			$chain[] = [
				'url'   => get_permalink( $page->ID ),
				'title' => get_the_title( $page ),
			];
			$pid = (int) $page->post_parent;
		}

		return array_reverse( $chain );
	}

	private function resolveHomeTextForDisplay( string $stored ): string {
		$trimmed = trim( $stored );
		if ( $trimmed === '' || $trimmed === self::DEFAULT_HOME_TEXT ) {
			return __( 'Home', 'wp-powersuite' );
		}

		return $stored;
	}

	private function isEnabledPostType( string $post_type ): bool {
		return isset( $this->getSettings()['post_types_lookup'][ $post_type ] );
	}

	/**
	 * @return list<string>
	 */
	public static function getAllowedPostTypes(): array {
		$excluded = [ 'attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset', 'oembed_cache', 'user_request', 'wp_block' ];

		return array_values(
			array_filter(
				get_post_types( [ 'public' => true ], 'names' ),
				static fn( string $slug ): bool => ! in_array( $slug, $excluded, true )
			)
		);
	}

	private function getSettings(): array {
		if ( $this->settings_cache !== null ) {
			return $this->settings_cache;
		}

		$raw   = $this->moduleSettings()->all( [] );
		$raw   = is_array( $raw ) ? $raw : [];
		$allow = array_flip( self::getAllowedPostTypes() );

		$types = isset( $raw['post_types'] ) && is_array( $raw['post_types'] )
			? array_values( array_filter( array_map( 'sanitize_key', $raw['post_types'] ) ) )
			: [ 'post', 'page' ];

		$types = array_values(
			array_filter(
				$types,
				static fn( string $slug ): bool => $slug !== '' && isset( $allow[ $slug ] )
			)
		);

		if ( $types === [] ) {
			foreach ( [ 'post', 'page' ] as $fallback ) {
				if ( isset( $allow[ $fallback ] ) ) {
					$types[] = $fallback;
				}
			}
		}

		$raw_auto = isset( $raw['auto_display'] ) ? (string) $raw['auto_display'] : 'none';
		$home_raw = sanitize_text_field( (string) ( $raw['home_text'] ?? self::DEFAULT_HOME_TEXT ) );
		$home_txt = function_exists( 'mb_substr' ) ? mb_substr( $home_raw, 0, 120 ) : substr( $home_raw, 0, 120 );

		$this->settings_cache = [
			'separator'          => $this->sanitizeSeparator( (string) ( $raw['separator'] ?? '›' ) ),
			'home_text'          => $home_txt !== '' ? $home_txt : self::DEFAULT_HOME_TEXT,
			'auto_display'       => in_array( $raw_auto, [ 'none', 'before', 'after' ], true ) ? $raw_auto : 'none',
			'post_types'         => $types,
			'post_types_lookup'  => array_fill_keys( $types, true ),
		];

		return $this->settings_cache;
	}
}
