<?php
/**
 * File Path: includes/shortcodes/class-mbs-shortcode-collection.php
 *
 * [mbs_collection slug="x"] Shortcode -- SHC-3
 *
 * Renders a single collection's type label, description, optional PRO reading
 * order grid (no position badges -- collection order implies sequence but not
 * strict numbering), or date-order fallback -- all inline, without calling
 * get_header() / get_footer(). Feature-for-feature equivalent of
 * taxonomy-mbs-collection.php.
 *
 * Extends MBS_Shortcode_Taxonomy_Base (D-010, Session 117) which handles
 * the shared scaffold: license gate, atts normalisation, slug + term
 * lookup, and the outer div/header HTML.
 *
 * Overrides:
 *   render_extra_header() -- outputs the collection type label inside <header>.
 *
 * Attributes:
 *   slug     (string, required) -- term slug for mbs_collection
 *   per_page (int, default 20)  -- books per page in date-order fallback; -1 = all.
 *                                  Ignored when reading order is active.
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */

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

class MBS_Shortcode_Collection extends MBS_Shortcode_Taxonomy_Base { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- mbs_/MBS_ prefix is correct; scanner not configured with plugin prefix

	protected static function get_taxonomy(): string {
		return MBS_TAX_COLLECTION;
	}

	protected static function get_shortcode_tag(): string {
		return 'mbs_collection';
	}

	/**
	 * F-BNR-C: Render the collection banner image (PRO only) after the archive header.
	 *
	 * @param WP_Term $term The resolved mbs_collection term.
	 * @return void
	 */
	protected static function render_after_header( WP_Term $term ): void {
		if ( ! mbs_is_pro() ) {
			return;
		}
		$banner_id = (int) get_term_meta( (int) $term->term_id, 'mbs_collection_banner_id', true );
		if ( ! $banner_id ) {
			return;
		}
		?>
		<div class="mbs-collection-banner">
			<?php echo wp_get_attachment_image( // R5-exempt: collection banner image, not book cover
				$banner_id,
				'full',
				false,
				array(
					'class' => 'mbs-collection-banner-img',
					'alt'   => $term->name,
				)
			); ?>
		</div>
		<?php
	}

	/**
	 * Output the collection type label inside <header>, after <h2>.
	 *
	 * @param WP_Term $term The resolved mbs_collection term.
	 * @return void
	 */
	protected static function render_extra_header( WP_Term $term ): void {
		$type_slug  = (string) get_term_meta( (int) $term->term_id, 'mbs_collection_type', true );
		$type_label = MBS_Taxonomy_Collection::get_type_label( $type_slug );
		if ( ! $type_label ) {
			return;
		}
		?>
		<p class="mbs-collection-type">
			<span class="mbs-collection-type-label"><?php echo esc_html( $type_label ); ?></span>
		</p>
		<?php
	}

	/**
	 * Emit the PRO reading-order grid or date-order fallback for the collection term.
	 *
	 * CE-2: Reading order is PRO-gated. No position badges regardless of layout
	 * (per SHC-6 compatibility table).
	 *
	 * @param WP_Term $term     The resolved mbs_collection term.
	 * @param int     $per_page Books per page for the date-order fallback.
	 * @return void
	 */
	protected static function render_body( WP_Term $term, int $per_page ): void {
		$term_id = (int) $term->term_id;

		// CE-2: Reading order -- PRO only. No position badges regardless of layout.
		$use_reading_order = mbs_is_pro()
		                     && MBS_Collection_Reading_Order_DAO::has_persisted_order( $term_id );

		// SHC-6: Collections never render position badges (per spec).
		$layout_obj = MBS_Layout_Registry::resolve_for_term( $term_id, 'grid' );

		if ( $use_reading_order ) {
			// CE-2: Reading order -- PRO. Load full DAO sequence (per_page ignored).
			// No position badges for collections (per spec).
			$ordered_ids = MBS_Collection_Reading_Order_DAO::get_ordered_book_ids( $term_id );
			$ro_query    = new WP_Query( array(
				'post_type'      => MBS_POST_TYPE,
				'posts_per_page' => count( $ordered_ids ),
				'post__in'       => $ordered_ids,
				'orderby'        => 'post__in',
				'post_status'    => 'publish',
			) );
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo $layout_obj->render( $ro_query );
		} else {
			// Date-order fallback (FREE or no persisted reading order).
			$date_query = new WP_Query( array(
				'post_type'      => MBS_POST_TYPE,
				'posts_per_page' => $per_page,
				'post_status'    => 'publish',
				'orderby'        => 'date',
				'order'          => 'DESC',
				'no_found_rows'  => true,
				'tax_query'      => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- standard WP query pattern; VIP rule does not apply to this plugin
					array(
						'taxonomy' => MBS_TAX_COLLECTION,
						'field'    => 'term_id',
						'terms'    => $term_id,
					),
				),
			) );
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo $layout_obj->render( $date_query );
		}
	}
}
