<?php
/**
 * Shared Courses helpers for the dynamic course-link grid.
 *
 * Used by BOTH bw/table-link (its "courses" variant) and the standalone
 * bw/course-table block, so the query and the modal body never diverge — the
 * same rationale as inc/bw-staff-profile.php for the staff blocks.
 *
 * @package kadence-child
 */

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'bw_course_query' ) ) {
	/**
	 * Pull a link list from the Courses post type, optionally filtered by one
	 * of its taxonomies.
	 *
	 * Accepts NORMALISED keys (each block maps its own attribute names onto
	 * these): tax (slug), terms (int[]), relation (IN|AND), orderby
	 * (title|menu_order|date), order (asc|desc), limit (0 = all), exclude
	 * (int[] of course IDs to hide on the front end without touching the data),
	 * ap_only (bool — restrict to courses flagged AP via the course_ap field),
	 * elective_only (bool — restrict to courses flagged elective via course_elective).
	 *
	 * @param array $args Normalised query args.
	 * @return array List of cells: array{ label:string, url:string, full:bool, id:int }.
	 */
	function bw_course_query( $args ) {
		$post_type = 'course';
		if ( ! post_type_exists( $post_type ) ) {
			return array();
		}

		// Orderby / order, both whitelisted.
		$orderby = $args['orderby'] ?? 'title';
		if ( ! in_array( $orderby, array( 'title', 'menu_order', 'date' ), true ) ) {
			$orderby = 'title';
		}
		$order = ( 'desc' === strtolower( (string) ( $args['order'] ?? 'asc' ) ) ) ? 'DESC' : 'ASC';

		// Limit: 0 (or less) means "all", hard-capped so a stray block can't run away.
		$limit = (int) ( $args['limit'] ?? 0 );
		$limit = ( $limit > 0 ) ? min( $limit, 200 ) : 200;

		$query_args = array(
			'post_type'              => $post_type,
			'post_status'            => 'publish',
			'posts_per_page'         => $limit,
			'orderby'                => $orderby,
			'order'                  => $order,
			'no_found_rows'          => true,
			'ignore_sticky_posts'    => true,
			'update_post_meta_cache' => false,
			'update_post_term_cache' => false,
		);
		if ( 'menu_order' === $orderby ) {
			$query_args['orderby'] = 'menu_order title';
		}

		// Exclude specific courses from THIS block's output only. Stored on the
		// block, never on the post — the courses stay published and untouched in
		// the back end, they just don't render here.
		$exclude = array();
		foreach ( (array) ( $args['exclude'] ?? array() ) as $e ) {
			$e = (int) $e;
			if ( $e > 0 ) {
				$exclude[] = $e;
			}
		}
		if ( $exclude ) {
			$query_args['post__not_in'] = $exclude;
		}

		// Optional "AP" / "elective" filters. Neither is a taxonomy — they live in
		// the course_ap / course_elective meta fields ('1' = yes), so they need a
		// meta_query rather than a tax_query. Both fields are set on every course
		// (ACF), so a simple '=' '1' match is enough. When both are on, all clauses
		// must match (relation AND).
		$meta_clauses = array();
		if ( ! empty( $args['ap_only'] ) ) {
			$meta_clauses[] = array( 'key' => 'course_ap', 'value' => '1', 'compare' => '=' );
		}
		if ( ! empty( $args['elective_only'] ) ) {
			$meta_clauses[] = array( 'key' => 'course_elective', 'value' => '1', 'compare' => '=' );
		}
		if ( $meta_clauses ) {
			if ( count( $meta_clauses ) > 1 ) {
				$meta_clauses['relation'] = 'AND';
			}
			$query_args['meta_query'] = $meta_clauses;
		}

		// Taxonomy filter. Supports MULTIPLE taxonomies via `filters` (each a clause
		// of { tax, terms[], operator }); falls back to the single `tax`/`terms`/
		// `relation` form for callers that still use it (e.g. bw/table-link). Only
		// taxonomies actually attached to courses are honoured.
		$obj_taxes = get_object_taxonomies( $post_type );

		/** Build one validated tax_query clause, or null. */
		$build_clause = function ( $tax, $terms_in, $operator ) use ( $obj_taxes ) {
			$tax = sanitize_key( (string) $tax );
			if ( '' === $tax || ! in_array( $tax, $obj_taxes, true ) ) {
				return null;
			}
			$terms = array();
			foreach ( (array) $terms_in as $t ) {
				$t = (int) $t;
				if ( $t > 0 ) {
					$terms[] = $t;
				}
			}
			if ( ! $terms ) {
				return null;
			}
			$operator = strtoupper( (string) $operator );
			if ( ! in_array( $operator, array( 'IN', 'AND', 'NOT IN' ), true ) ) {
				$operator = 'IN';
			}
			return array(
				'taxonomy' => $tax,
				'field'    => 'term_id',
				'terms'    => $terms,
				'operator' => $operator,
			);
		};

		$tax_query = array();
		if ( ! empty( $args['filters'] ) && is_array( $args['filters'] ) ) {
			foreach ( $args['filters'] as $f ) {
				$clause = $build_clause(
					$f['tax'] ?? '',
					$f['terms'] ?? array(),
					$f['operator'] ?? 'IN'
				);
				if ( $clause ) {
					$tax_query[] = $clause;
				}
			}
		} else {
			// Legacy single-taxonomy form.
			$clause = $build_clause(
				$args['tax'] ?? '',
				$args['terms'] ?? array(),
				$args['relation'] ?? 'IN'
			);
			if ( $clause ) {
				$tax_query[] = $clause;
			}
		}

		if ( count( $tax_query ) > 1 ) {
			$rel                    = strtoupper( (string) ( $args['filter_relation'] ?? 'AND' ) );
			$tax_query['relation']  = ( 'OR' === $rel ) ? 'OR' : 'AND';
		}
		if ( $tax_query ) {
			$query_args['tax_query'] = $tax_query;
		}

		$q   = new WP_Query( $query_args );
		$out = array();
		foreach ( $q->posts as $p ) {
			$out[] = array(
				'label' => get_the_title( $p ),
				'url'   => get_permalink( $p ),
				'full'  => false,
				'id'    => (int) $p->ID, // carried so the modal mode can pull body + credit
			);
		}
		return $out;
	}
}

if ( ! function_exists( 'bw_course_modal_html' ) ) {
	/**
	 * Modal body for a single course — title, description and the ACF
	 * "Ministry Credit Awarded" line. Mirrors the course pop-up on
	 * brentwood.ca (e.g. /arts/acting-and-drama). Escaped here because it is
	 * embedded inside an inert <template> and cloned into the DOM by view.js.
	 *
	 * @param int $post_id Course post ID.
	 * @return string
	 */
	function bw_course_modal_html( $post_id ) {
		$post = get_post( $post_id );
		if ( ! $post ) {
			return '';
		}
		$title  = get_the_title( $post );
		$body   = trim( (string) $post->post_content );
		$credit = trim( (string) get_post_meta( $post->ID, 'course_credit', true ) );

		$out  = '<div class="bw-tl-modal__inner">';
		$out .= '<h2 class="bw-tl-modal__title">' . esc_html( $title ) . '</h2>';
		if ( '' !== $body ) {
			// wpautop + kses (not the_content) to avoid re-running do_blocks inside
			// a block render — same approach as the staff profile modal.
			$out .= '<div class="bw-tl-modal__body">' . wp_kses_post( wpautop( $body ) ) . '</div>';
		}
		if ( '' !== $credit ) {
			$out .= '<div class="bw-tl-modal__meta">'
				. '<span class="bw-tl-modal__meta-label">Ministry Credit Awarded:</span> '
				. '<span class="bw-tl-modal__meta-value">' . esc_html( $credit ) . '</span>'
				. '</div>';
		}
		$out .= '</div>';
		return $out;
	}
}
