<?php
/**
 * Brentwood 100 Grid — front-end render.
 *
 * Renders every published `bw_hundred` item as a tile in one CSS-grid mosaic.
 * Three tile styles (ACF `hundred_type`):
 *   - modal   : numbered cover tile → opens a pop-up (reuses the shared bw-tl
 *               modal: a .bw-tl__modal-trigger + inert <template>, cloned by
 *               bw-table-link-view into one shared dialog).
 *   - inline  : the story (cover + title + body) shown directly in the grid.
 *   - montage : a static numbered photo tile with a caption, no pop-up.
 *
 * The whole tile list is cached in a transient (busted on any bw_hundred edit —
 * see inc/bw-hundred.php), so each request serves cached HTML. The only per-visit
 * work is the client-side shuffle + #anchor deep-link in view.js.
 *
 * @var array $attributes Block attributes.
 */

defined( 'ABSPATH' ) || exit;

require_once get_stylesheet_directory() . '/inc/bw-hundred.php';

$columns   = max( 2, min( 6, (int) ( $attributes['columns'] ?? 4 ) ) );
$cache_key = 'bw_hundred_grid_c' . $columns;
$inner     = get_transient( $cache_key );

if ( false === $inner ) {
	$posts = bw_hundred_query();
	if ( empty( $posts ) ) {
		return;
	}
	$inner = '';
	foreach ( $posts as $p ) {
		$type   = get_field( 'hundred_type', $p->ID ) ?: 'modal';
		$num    = get_field( 'hundred_number', $p->ID );
		$span   = max( 1, min( 4, (int) ( get_field( 'hundred_span', $p->ID ) ?: 1 ) ) );
		$vspan  = max( 1, min( 2, (int) ( get_field( 'hundred_vspan', $p->ID ) ?: 1 ) ) );
		$cap    = (string) get_field( 'hundred_caption', $p->ID );
		$anchor = $p->post_name;
		$cover  = has_post_thumbnail( $p )
			? get_the_post_thumbnail( $p, 'large', array( 'class' => 'bw100__img', 'loading' => 'lazy' ) )
			: '';
		$badge  = ( '' !== $num && null !== $num ) ? '<span class="bw100__num">' . esc_html( $num ) . '</span>' : '';
		$capovl = ( '' !== $cap ) ? '<span class="bw100__cap">' . esc_html( $cap ) . '</span>' : '';
		$cellst = '--bw100-span:' . $span . ';--bw100-vspan:' . $vspan . ';';

		if ( 'inline' === $type ) {
			$body   = do_blocks( $p->post_content );
			$inner .= '<div class="bw100__cell bw100__cell--inline" id="' . esc_attr( $anchor ) . '" style="' . $cellst . '">'
				. ( '' !== $cover ? '<div class="bw100__inline-media">' . $cover . $badge . '</div>' : '' )
				. '<div class="bw100__inline-text">'
					. ( '' === $cover ? $badge : '' )
					. '<h3 class="bw100__inline-title">' . esc_html( get_the_title( $p ) ) . '</h3>'
					. '<div class="bw100__inline-body">' . $body . '</div>'
				. '</div>'
				. '</div>';
		} elseif ( 'montage' === $type ) {
			$inner .= '<div class="bw100__cell bw100__cell--montage" id="' . esc_attr( $anchor ) . '" style="' . $cellst . '">'
				. '<figure class="bw100__tile bw100__tile--static">' . $cover . $badge . $capovl . '</figure>'
				. '</div>';
		} else { // modal (default)
			// bw-tl__cell so the shared bw-table-link-view finds the cell + its
			// <template.bw-tl__course> when a trigger is clicked.
			$inner .= '<div class="bw100__cell bw100__cell--modal bw-tl__cell" data-bw100-anchor="' . esc_attr( $anchor ) . '" style="' . $cellst . '">'
				. '<button type="button" class="bw100__tile bw-tl__modal-trigger" aria-haspopup="dialog" aria-label="' . esc_attr( get_the_title( $p ) ) . '">'
					. $cover . $badge . $capovl
				. '</button>'
				. '<template class="bw-tl__course">' . bw_hundred_modal_html( $p ) . '</template>' // phpcs:ignore WordPress.Security.EscapeOutput -- escaped in helper
				. '</div>';
		}
	}
	set_transient( $cache_key, $inner, DAY_IN_SECONDS );
}

$style = '--bw100-cols:' . $columns . ';';

// Grid starts hidden (opacity:0) and view.js reveals it after shuffling, to
// avoid a reorder flash. <noscript> reveals it when JS is off.
printf(
	'<div %s><noscript><style>.bw100__grid{opacity:1 !important}</style></noscript><div class="bw100__grid">%s</div></div>',
	get_block_wrapper_attributes( array( 'class' => 'bw100 bw-tl bw-tl--courses', 'style' => $style ) ), // phpcs:ignore WordPress.Security.EscapeOutput
	$inner // phpcs:ignore WordPress.Security.EscapeOutput -- assembled from escaped parts above / cached
);
