<?php
/**
 * File Path: includes/shortcodes/class-mbs-shortcode-books.php
 *
 * My Book Showroom — [mbs_books] Shortcode
 *
 * Handles the multi-book shortcode using layout registry.
 *
 * @package MyBookShowroom
 * @since   1.0.0
 */

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

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

	/**
	 * Render [mbs_books] shortcode.
	 *
	 * @param array $atts Shortcode attributes (raw from WordPress or caller).
	 * @return string Rendered HTML.
	 */
	public static function render( array $atts ): string {
		if ( ! mbs_is_registered() ) {
			return '';
		}

		// SC-002 / BLK-001: shortcode_atts() discards keys not in the defaults array,
		// so query-layer attributes (genre, author, series, tag, limit, orderby) were
		// silently stripped before MBS_Book_Query::build() ever saw them.
		// Fix: capture raw atts first, apply shortcode_atts only for render-layer keys,
		// then merge back so query-layer keys pass through intact.
		$raw_atts    = $atts;
		$render_atts = shortcode_atts( array(
			'layout'          => mbs_get_setting( 'formatting', 'default_layout', 'hero' ),
			'columns'         => 3,
			'show_pagination' => true,
		), $atts, 'mbs_books' );

		// ADM-014: Sanitize query-layer pass-through attributes before they reach
		// MBS_Book_Query::build(). Numeric ID fields go through absint(); taxonomy
		// slug-type values go through sanitize_key().
		$sanitized_query = array();
		$int_keys        = array( 'per_page', 'columns', 'offset', 'term_id', 'limit', 'posts_per_page' );
		$slug_keys       = array( 'author', 'series', 'genre', 'tag', 'collection', 'universe', 'orderby', 'order', 'layout' );
		foreach ( $int_keys as $key ) {
			if ( isset( $raw_atts[ $key ] ) ) {
				$sanitized_query[ $key ] = absint( $raw_atts[ $key ] );
			}
		}
		foreach ( $slug_keys as $key ) {
			if ( isset( $raw_atts[ $key ] ) ) {
				$sanitized_query[ $key ] = sanitize_key( $raw_atts[ $key ] );
			}
		}

		$query_args = MBS_Book_Query::build( array_merge( $render_atts, $sanitized_query ) );

		// V2-G-002: no_found_rows must be false when pagination is enabled so
		// WP_Query populates max_num_pages correctly.
		$show_pagination = in_array( strtolower( (string) ( $render_atts['show_pagination'] ?? '' ) ), array( '1', 'true', 'yes', 'on' ), true );
		$query_args['no_found_rows'] = ! $show_pagination;

		$query      = new WP_Query( $query_args );

		$layout = MBS_Layout_Registry::get_layout( $render_atts['layout'] );

		$output = $layout->render( $query ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- trusted HTML from layout class

		// V2-G-002: Emit pagination controls when show_pagination is truthy.
		if ( $show_pagination && $query->max_num_pages > 1 ) {
			$pagination = paginate_links( array(
				'total'   => $query->max_num_pages,
				'current' => max( 1, get_query_var( 'paged' ) ),
			) );
			if ( $pagination ) {
				$output .= '<nav class="mbs-pagination">' . $pagination . '</nav>';
			}
		}

		return $output;
	}
}
