<?php
/**
 * Brentwood Table Accordion — front-end render.
 *
 * A link table (or link grid) whose cells are triggers: clicking one expands a
 * rich content panel BELOW the table. Cells and panels both come from the block's
 * bw/accordion-item children — each child carries one cell label (+ optional
 * full-width flag) and the panel body as its own InnerBlocks. This parent draws
 * the whole thing: the table of <a> triggers and, after it, the hidden panels,
 * wired together by a per-item id. view.js (bw-table-accordion-view) toggles them.
 *
 * Layout mirrors bw/table-link (table = bordered cells with optional full-width
 * colspan rows; grid = bordered link boxes). The expand interaction mirrors
 * brentwood.ca's course-selection #anchor expanders, but self-contained in one
 * block instead of separate anchor-linked sections.
 *
 * @var array    $attributes Block attributes.
 * @var string   $content    Inner content (unused — we render children ourselves).
 * @var WP_Block $block      Block instance (its inner_blocks are the items).
 */

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'bw_ta_color' ) ) {
	function bw_ta_color( $value, $default = '' ) {
		$value = trim( (string) $value );
		if ( '' === $value ) {
			return $default;
		}
		if ( preg_match( '/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i', $value )
			|| preg_match( '/^rgba?\(\s*[0-9.,%\s\/]+\)$/i', $value )
			|| preg_match( '/^var\(\s*--[a-z0-9\-]+\s*\)$/i', $value ) ) {
			return $value;
		}
		return $default;
	}
}

if ( ! function_exists( 'bw_ta_unique_id' ) ) {
	/**
	 * Turn a cell label into its anchor id (slug of the label), kept unique across
	 * every Table Accordion rendered in the request so two cells — or two blocks —
	 * sharing a label still get distinct ids (second one gets "-2", "-3", …).
	 */
	function bw_ta_unique_id( $label ) {
		static $used = array();
		$base = sanitize_title( $label );
		if ( '' === $base ) {
			$base = 'panel';
		}
		$id = $base;
		$n  = 2;
		while ( isset( $used[ $id ] ) ) {
			$id = $base . '-' . $n;
			$n++;
		}
		$used[ $id ] = true;
		return $id;
	}
}

if ( ! function_exists( 'bw_ta_cell' ) ) {
	/**
	 * A table cell: an accordion trigger (expands its panel) or a plain link
	 * (navigates to the item's URL), per the item's behavior. Mixed cells in one
	 * table are fine.
	 */
	function bw_ta_cell( $cell, $chevron ) {
		$inner = esc_html( $cell['label'] ) . $chevron; // $chevron is a safe literal entity
		if ( 'link' === $cell['behavior'] ) {
			if ( '' !== $cell['url'] ) {
				return '<a class="bw-ta__link" href="' . esc_url( $cell['url'] ) . '">' . $inner . '</a>';
			}
			return '<span class="bw-ta__link">' . $inner . '</span>';
		}
		// "scroll-ignore" opts the link out of Kadence's global anchor smooth-scroll
		// (themes/kadence navigation.min.js) — our view.js handles the click, so we
		// don't want Kadence also scrolling to the panel id.
		return '<a class="bw-ta__link bw-ta__trigger scroll-ignore" href="#' . esc_attr( $cell['id'] ) . '"'
			. ' aria-controls="' . esc_attr( $cell['id'] ) . '" aria-expanded="false"'
			. ' data-bw-ta-trigger>' . $inner . '</a>';
	}
}

// ── sanitize attributes ──────────────────────────────────────────────────────
$variant      = ( 'grid' === ( $attributes['variant'] ?? 'table' ) ) ? 'grid' : 'table';
$columns      = max( 1, min( 6, (int) ( $attributes['columns'] ?? 3 ) ) );
$show_chevron = ! empty( $attributes['showChevron'] );
$single_open  = ! isset( $attributes['singleOpen'] ) || ! empty( $attributes['singleOpen'] );
$panel_width  = max( 20, min( 100, (int) ( $attributes['panelWidth'] ?? 100 ) ) );
$panel_align  = $attributes['panelAlign'] ?? 'left';
if ( ! in_array( $panel_align, array( 'left', 'center', 'right' ), true ) ) {
	$panel_align = 'left';
}
$primary = bw_ta_color( $attributes['primaryColor'] ?? '', '#cc0000' );
$border  = bw_ta_color( $attributes['borderColor']  ?? '', '#d9d9d9' );
$layout  = ( 'revealed' === ( $attributes['layout'] ?? 'default' ) ) ? 'revealed' : 'default';
$bg      = bw_ta_color( $attributes['bgColor'] ?? '', '' );
$bg_var  = ( '' !== $bg ) ? '--bw-ta-bg:' . esc_attr( $bg ) . ';' : '';

// Spacing (revealed layout) — integer px per side, applied to the panel body.
$m_top    = (int) ( $attributes['marginTop']    ?? 0 );
$m_right  = (int) ( $attributes['marginRight']  ?? 0 );
$m_bottom = (int) ( $attributes['marginBottom'] ?? 0 );
$m_left   = (int) ( $attributes['marginLeft']   ?? 0 );
$p_top    = (int) ( $attributes['paddingTop']    ?? 0 );
$p_right  = (int) ( $attributes['paddingRight']  ?? 0 );
$p_bottom = (int) ( $attributes['paddingBottom'] ?? 0 );
$p_left   = (int) ( $attributes['paddingLeft']   ?? 0 );
$spacing_var = sprintf(
	'--bw-ta-m:%dpx %dpx %dpx %dpx;--bw-ta-p:%dpx %dpx %dpx %dpx;',
	$m_top, $m_right, $m_bottom, $m_left,
	$p_top, $p_right, $p_bottom, $p_left
);

// ── revealed layout ──────────────────────────────────────────────────────────
// The whole block is hidden until an in-page link to its anchor is clicked
// (view.js reveals + scrolls; the × hides it and clears the hash). The content is
// free-form InnerBlocks ($content) — editors build any panel (e.g. a multi-column
// nationalities list) instead of the cell/panel table. Mirrors the FAQ "revealed"
// panel, but with blank InnerBlocks rather than accordion-item children.
if ( 'revealed' === $layout ) {
	if ( '' === trim( (string) $content ) ) {
		return;
	}
	$anchor     = sanitize_title( $attributes['revealAnchor'] ?? '' );
	$has_anchor = ( '' !== $anchor );

	$close_btn = '<button type="button" class="bw-ta__close bw-ta__reveal-close" data-bw-ta-reveal-close aria-label="Close">'
		. '<svg viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">'
		. '<path fill="currentColor" d="M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 1 0 5.7 7.11L10.59 12 5.7 16.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z"></path>'
		. '</svg></button>';

	$style = '--bw-ta-primary:' . esc_attr( $primary ) . ';--bw-ta-border:' . esc_attr( $border ) . ';' . $bg_var . $spacing_var;

	$wrapper_args = array(
		'class' => 'bw-ta bw-ta--reveal' . ( $has_anchor ? ' is-hidden' : '' ),
		'style' => $style,
	);
	if ( $has_anchor ) {
		$wrapper_args['id'] = $anchor;
	}

	// The × lives INSIDE the reveal body (its positioning context) and is pinned
	// to that box's top-right corner with a fixed inset — see the CSS. Anchoring to
	// the body (not the outer wrapper) makes the × position independent of the
	// block's margin/padding: changing spacing moves the box, and the × rides with
	// it instead of drifting into a wrapping Row's clipped corner. Rendered last so
	// the body's real content stays the :first-child for the margin-trim rules.
	printf(
		'<div %s><div class="bw-ta__reveal-body">%s%s</div></div>',
		get_block_wrapper_attributes( $wrapper_args ), // phpcs:ignore WordPress.Security.EscapeOutput
		$content,   // phpcs:ignore WordPress.Security.EscapeOutput -- InnerBlocks (self-escaped)
		$close_btn  // phpcs:ignore WordPress.Security.EscapeOutput -- literal markup
	);
	return;
}

// ── collect items from the accordion-item children ───────────────────────────
$items = array();
if ( isset( $block->inner_blocks ) ) {
	foreach ( $block->inner_blocks as $child ) {
		if ( 'bw/accordion-item' !== $child->name ) {
			continue;
		}
		$label = sanitize_text_field( $child->attributes['label'] ?? '' );
		if ( '' === $label ) {
			continue;
		}
		$behavior = ( 'link' === ( $child->attributes['behavior'] ?? 'accordion' ) ) ? 'link' : 'accordion';
		$item = array(
			'label'    => $label,
			'full'     => ! empty( $child->attributes['fullWidth'] ),
			'behavior' => $behavior,
			'url'      => '',
			'id'       => '',
			'content'  => '',
		);
		if ( 'link' === $behavior ) {
			$item['url'] = esc_url_raw( $child->attributes['url'] ?? '' );
		} else {
			$item['id']      = bw_ta_unique_id( $label );
			$item['content'] = $child->render(); // the panel body (child InnerBlocks)
		}
		$items[] = $item;
	}
}

if ( empty( $items ) ) {
	return;
}

$chevron = $show_chevron ? '&nbsp;&gt;' : '';

// ── trigger table / grid ─────────────────────────────────────────────────────
if ( 'table' === $variant ) {
	// Group items into rows of $columns; a full-width item owns a colspan row.
	$rows = array();
	$buf  = array();
	foreach ( $items as $cell ) {
		if ( $cell['full'] ) {
			if ( $buf ) {
				$rows[] = array( 'cells' => $buf );
				$buf    = array();
			}
			$rows[] = array( 'cells' => array( $cell ), 'span' => $columns );
		} else {
			$buf[] = $cell;
			if ( count( $buf ) === $columns ) {
				$rows[] = array( 'cells' => $buf );
				$buf    = array();
			}
		}
	}
	if ( $buf ) {
		$rows[] = array( 'cells' => $buf, 'pad' => true );
	}

	$table_html = '<table class="bw-ta__table"><tbody>';
	foreach ( $rows as $row ) {
		$cells = $row['cells'];
		$n     = count( $cells );
		$table_html .= '<tr>';
		foreach ( $cells as $i => $cell ) {
			$colspan = 1;
			if ( ! empty( $row['span'] ) ) {
				$colspan = $row['span'];
			} elseif ( ! empty( $row['pad'] ) && $i === $n - 1 ) {
				$colspan = $columns - ( $n - 1 );
			}
			$cs = ( $colspan > 1 ) ? ' colspan="' . (int) $colspan . '"' : '';
			$table_html .= '<td' . $cs . '>' . bw_ta_cell( $cell, $chevron ) . '</td>';
		}
		$table_html .= '</tr>';
	}
	$table_html .= '</tbody></table>';
} else {
	$table_html = '<div class="bw-ta__grid" style="--bw-ta-cols:' . (int) $columns . '">';
	foreach ( $items as $cell ) {
		$full = $cell['full'] ? ' bw-ta__cell--full' : '';
		$table_html .= '<div class="bw-ta__cell' . $full . '">' . bw_ta_cell( $cell, $chevron ) . '</div>';
	}
	$table_html .= '</div>';
}

// ── panels (hidden until expanded) ───────────────────────────────────────────
$close = '<button type="button" class="bw-ta__close" aria-label="Close">'
	. '<svg viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">'
	. '<path fill="currentColor" d="M18.3 5.71a1 1 0 0 0-1.41 0L12 10.59 7.11 5.7A1 1 0 1 0 5.7 7.11L10.59 12 5.7 16.89a1 1 0 1 0 1.41 1.41L12 13.41l4.89 4.89a1 1 0 0 0 1.41-1.41L13.41 12l4.89-4.89a1 1 0 0 0 0-1.4z"></path>'
	. '</svg></button>';

$panels_html = '<div class="bw-ta__panels">';
foreach ( $items as $cell ) {
	if ( 'accordion' !== $cell['behavior'] ) {
		continue; // link cells have no panel
	}
	$panels_html .= '<div class="bw-ta__panel bw-ta__panel--' . esc_attr( $panel_align ) . '"'
		. ' id="' . esc_attr( $cell['id'] ) . '" data-bw-ta-panel role="region"'
		. ' style="--bw-ta-panel-w:' . $panel_width . '%">'
		. '<div class="bw-ta__panel-inner">' . $close . $cell['content'] . '</div>'
		. '</div>';
}
$panels_html .= '</div>';

// ── wrapper ──────────────────────────────────────────────────────────────────
$style = '--bw-ta-primary:' . esc_attr( $primary ) . ';--bw-ta-border:' . esc_attr( $border ) . ';' . $bg_var;

printf(
	'<div %s data-single-open="%s">%s%s</div>',
	get_block_wrapper_attributes( array( 'class' => 'bw-ta bw-ta--' . $variant, 'style' => $style ) ), // phpcs:ignore WordPress.Security.EscapeOutput
	$single_open ? '1' : '0', // phpcs:ignore WordPress.Security.EscapeOutput -- literal
	$table_html,  // phpcs:ignore WordPress.Security.EscapeOutput -- assembled from escaped parts
	$panels_html  // phpcs:ignore WordPress.Security.EscapeOutput -- close is literal, content is InnerBlocks (self-escaped)
);
