<?php
/**
 * Answyr Knowledge — native knowledge-base module.
 *
 * Houses knowledge-base articles inside the plugin as a CPT (answyr_kb)
 * + taxonomy (answyr_kb_category) so they're natively connected to the AI grounding.
 * Retrieval picks the CPT up automatically.
 *
 * The KB is INTERNAL by default: not on any public archive and excluded from
 * site search. To make it public, an admin publishes a page holding the
 * [answyr_kb] shortcode (there's a one-click button in Settings). Single
 * articles remain reachable by URL so that index can link to them.
 *
 * @package Answyr
 */

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

final class Answyr_Knowledge_Module extends Answyr_Module {

	public const CPT = 'answyr_kb';
	public const TAX = 'answyr_kb_category';

	public function id(): string {
		return 'knowledge';
	}

	public function label(): string {
		return __( 'Knowledge', 'answyr' );
	}

	public function register(): void {
		add_action( 'init', array( $this, 'register_types' ) );
		add_filter( 'template_include', array( $this, 'template' ) );
		add_shortcode( 'answyr_kb', array( $this, 'render_index' ) );
	}

	/** Single-article URL base — falls back if something already owns 'kb'. */
	public static function slug(): string {
		$slug = post_type_exists( 'kb' ) ? 'support-kb' : 'kb';
		return (string) apply_filters( 'answyr_kb_slug', $slug );
	}

	public function register_types(): void {
		$slug = self::slug();

		register_post_type(
			self::CPT,
			array(
				'labels'              => array(
					'name'          => __( 'Knowledge', 'answyr' ),
					'singular_name' => __( 'Article', 'answyr' ),
					'add_new_item'  => __( 'Add New Article', 'answyr' ),
					'edit_item'     => __( 'Edit Article', 'answyr' ),
					'search_items'  => __( 'Search Knowledge', 'answyr' ),
					'not_found'     => __( 'No articles found.', 'answyr' ),
				),
				// Internal by default: manageable + REST + grounded, but no archive
				// and out of site search. Single articles stay reachable by URL so a
				// published [answyr_kb] index page can link to them.
				'public'              => false,
				'show_ui'             => true,
				'show_in_rest'        => true,
				'publicly_queryable'  => true,
				'exclude_from_search' => true,
				'menu_icon'           => 'dashicons-book',
				'show_in_menu'        => 'answyr',
				'has_archive'         => false,
				'rewrite'             => array(
					'slug'       => $slug,
					'with_front' => false,
				),
				'supports'            => array( 'title', 'editor', 'excerpt', 'revisions', 'thumbnail', 'page-attributes', 'author' ),
			)
		);

		register_taxonomy(
			self::TAX,
			self::CPT,
			array(
				'labels'             => array(
					'name'          => __( 'Knowledge Categories', 'answyr' ),
					'singular_name' => __( 'Knowledge Category', 'answyr' ),
				),
				'public'             => false,
				'show_ui'            => true,
				'show_in_rest'       => true,
				'publicly_queryable' => true,
				'hierarchical'       => true,
				'show_admin_column'  => true,
				'rewrite'            => array(
					'slug'       => $slug . '-category',
					'with_front' => false,
				),
			)
		);

		// One-shot rewrite flush after activation so article URLs resolve.
		if ( get_option( 'answyr_flush_kb' ) ) {
			flush_rewrite_rules();
			delete_option( 'answyr_flush_kb' );
		}
	}

	/**
	 * Provide a clean fallback template for classic themes only. Block themes
	 * render the CPT through their own templates (better integration + SEO).
	 *
	 * @param string $template
	 */
	public function template( string $template ): string {
		if ( wp_is_block_theme() ) {
			return $template;
		}
		if ( is_singular( self::CPT ) && ! locate_template( 'single-' . self::CPT . '.php' ) ) {
			return ANSWYR_PATH . 'inc/modules/knowledge/templates/single.php';
		}
		if ( is_tax( self::TAX ) && ! locate_template( 'taxonomy-' . self::TAX . '.php' ) ) {
			return ANSWYR_PATH . 'inc/modules/knowledge/templates/archive.php';
		}
		return $template;
	}

	/** [answyr_kb] — a categorized index of knowledge-base articles. */
	public function render_index(): string {
		$terms = get_terms(
			array(
				'taxonomy'   => self::TAX,
				'hide_empty' => true,
			)
		);

		ob_start();
		echo '<div class="answyr-kb-index">';

		if ( is_array( $terms ) && $terms ) {
			foreach ( $terms as $term ) {
				printf(
					'<h3 class="ssd-cat"><a href="%s">%s</a></h3>',
					esc_url( (string) get_term_link( $term ) ),
					esc_html( $term->name )
				);
				$this->render_article_list(
					array(
						// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
						'tax_query' => array(
							array(
								'taxonomy' => self::TAX,
								'field'    => 'term_id',
								'terms'    => $term->term_id,
							),
						),
					)
				);
			}
		} else {
			$this->render_article_list( array() );
		}

		echo '</div>';
		return (string) ob_get_clean();
	}

	/** @param array<string,mixed> $extra_args */
	private function render_article_list( array $extra_args ): void {
		$query = new WP_Query(
			array_merge(
				array(
					'post_type'      => self::CPT,
					'posts_per_page' => 50,
					'orderby'        => array(
						'menu_order' => 'ASC',
						'title'      => 'ASC',
					),
					'no_found_rows'  => true,
				),
				$extra_args
			)
		);

		if ( ! $query->have_posts() ) {
			echo '<p>' . esc_html__( 'No articles yet.', 'answyr' ) . '</p>';
			return;
		}

		echo '<ul class="ssd-list">';
		while ( $query->have_posts() ) {
			$query->the_post();
			printf(
				'<li><a href="%s">%s</a></li>',
				esc_url( (string) get_permalink() ),
				esc_html( get_the_title() )
			);
		}
		echo '</ul>';
		wp_reset_postdata();
	}
}
