<?php
/**
 * Shared Staff helpers for the bw/team-modal and bw/instructor blocks.
 *
 * Both blocks query the `staff` post type (optionally filtered by the
 * `department` taxonomy) and open the SAME profile modal (.bw-tm__modal,
 * styled in blocks/team-modal/style.css, wired by blocks/team-modal/view.js).
 * The profile markup lives here so the two blocks never diverge.
 */

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'bw_staff_last_name' ) ) {
	/**
	 * Surname used for sorting staff.
	 *
	 * Prefers the explicit "Last Name" profile field (`staff_last_name`, from the
	 * Profile (self-service) box — see inc/bw-my-profile.php). Falls back to the
	 * last whitespace-separated token of the title, which is wrong for anyone
	 * with a two-word surname (e.g. "Sue Cheung Robinson" sorted under
	 * "Robinson", "Rebecca Day Reynolds" under "Reynolds") — hence the field.
	 *
	 * Resolved live at sort time, so there is no cached sort key to go stale:
	 * edit the Last Name field and the ordering follows immediately.
	 *
	 * @param WP_Post|int|string $post Staff post, post ID, or a raw name string.
	 * @return string
	 */
	function bw_staff_last_name( $post ) {
		$name = '';

		if ( $post instanceof WP_Post || is_numeric( $post ) ) {
			$id   = ( $post instanceof WP_Post ) ? (int) $post->ID : (int) $post;
			$last = trim( (string) get_post_meta( $id, 'staff_last_name', true ) );
			if ( '' !== $last ) {
				return $last;
			}
			$name = ( $post instanceof WP_Post ) ? (string) $post->post_title : (string) get_the_title( $id );
		} else {
			$name = (string) $post;
		}

		$name = trim( preg_replace( '/\s+/', ' ', $name ) );
		if ( '' === $name ) {
			return '';
		}
		$parts = explode( ' ', $name );
		return (string) end( $parts );
	}
}

if ( ! function_exists( 'bw_staff_query' ) ) {
	/**
	 * Ordered, optionally department-filtered list of published staff.
	 *
	 * @param array $a Keys: deptTerms (int[]), deptRelation (IN|AND),
	 *                 orderby (title|name_last|menu_order|date), order (asc|desc),
	 *                 limit (int, 0 = all).
	 * @return WP_Post[]
	 */
	function bw_staff_query( $a ) {
		if ( ! post_type_exists( 'staff' ) ) {
			return array();
		}

		// Explicit hand-picked staff (used by the instructor block's inline
		// variant). When given, these win outright: the exact posts in the
		// exact order chosen, ignoring department filter and ordering.
		$ids = array();
		foreach ( (array) ( $a['staffIds'] ?? array() ) as $id ) {
			$id = (int) $id;
			if ( $id > 0 ) {
				$ids[] = $id;
			}
		}
		if ( $ids ) {
			$q = new WP_Query( array(
				'post_type'           => 'staff',
				'post_status'         => 'publish',
				'post__in'            => $ids,
				'orderby'             => 'post__in', // preserve the picked order
				'posts_per_page'      => min( count( $ids ), 500 ),
				'no_found_rows'       => true,
				'ignore_sticky_posts' => true,
			) );
			return $q->posts;
		}

		$orderby = $a['orderby'] ?? 'name_last';
		if ( ! in_array( $orderby, array( 'title', 'name_last', 'menu_order', 'date' ), true ) ) {
			$orderby = 'name_last';
		}
		$order = ( 'desc' === strtolower( (string) ( $a['order'] ?? 'asc' ) ) ) ? 'DESC' : 'ASC';

		$limit = (int) ( $a['limit'] ?? 0 );
		$hard  = 500;
		$query_limit = ( 'name_last' === $orderby ) ? $hard : ( $limit > 0 ? min( $limit, $hard ) : $hard );

		// Hand-picked staff to hide (front-end only — the posts stay published).
		$exclude = array();
		foreach ( (array) ( $a['exclude'] ?? array() ) as $x ) {
			$x = (int) $x;
			if ( $x > 0 ) {
				$exclude[] = $x;
			}
		}

		$args = array(
			'post_type'           => 'staff',
			'post_status'         => 'publish',
			'posts_per_page'      => $query_limit,
			'orderby'             => ( 'name_last' === $orderby ) ? 'title' : $orderby,
			'order'               => $order,
			'no_found_rows'       => true,
			'ignore_sticky_posts' => true,
		);
		if ( $exclude ) {
			$args['post__not_in'] = $exclude;
		}
		if ( 'menu_order' === $orderby ) {
			$args['orderby'] = 'menu_order title';
		}

		$terms = array();
		foreach ( (array) ( $a['deptTerms'] ?? array() ) as $t ) {
			$t = (int) $t;
			if ( $t > 0 ) {
				$terms[] = $t;
			}
		}
		if ( $terms && taxonomy_exists( 'department' ) ) {
			$relation          = ( 'AND' === strtoupper( (string) ( $a['deptRelation'] ?? 'IN' ) ) ) ? 'AND' : 'IN';
			$args['tax_query'] = array(
				array(
					'taxonomy' => 'department',
					'field'    => 'term_id',
					'terms'    => $terms,
					'operator' => $relation,
				),
			);
		}

		$q     = new WP_Query( $args );
		$posts = $q->posts;

		if ( 'name_last' === $orderby ) {
			usort( $posts, function ( $x, $y ) use ( $order ) {
				// Pass the post (not just the title) so the explicit
				// "Last Name" profile field is used when it's set.
				$cmp = strcasecmp( bw_staff_last_name( $x ), bw_staff_last_name( $y ) );
				if ( 0 === $cmp ) {
					$cmp = strcasecmp( $x->post_title, $y->post_title );
				}
				return ( 'DESC' === $order ) ? -$cmp : $cmp;
			} );
			if ( $limit > 0 ) {
				$posts = array_slice( $posts, 0, $limit );
			}
		}

		return $posts;
	}
}

if ( ! function_exists( 'bw_staff_has_profile' ) ) {
	/** Whether a staff member has anything to show in a modal (bio or credentials). */
	function bw_staff_has_profile( $p ) {
		$bio  = trim( (string) $p->post_content );
		$cred = trim( (string) get_post_meta( $p->ID, 'staff_credentials', true ) );
		return ( '' !== $bio || '' !== $cred );
	}
}

if ( ! function_exists( 'bw_staff_profile_html' ) ) {
	/**
	 * The .bw-tm__profile markup that fills the shared modal: name, role,
	 * credentials (with mortarboard icon), photo (floated) and bio, closed by the
	 * hairline rule + Brentwood shield. Mirrors the live faculty profile pop-up.
	 *
	 * @param WP_Post $p       Staff post.
	 * @param string  $heading Heading tag for the name: 'h2' (default, for the
	 *                         modal/grids) or 'h1' (for the standalone single
	 *                         staff page, which needs a document heading).
	 * @return string Escaped HTML.
	 */
	function bw_staff_profile_html( $p, $heading = 'h2', $layout = 'default' ) {
		$heading = in_array( $heading, array( 'h1', 'h2', 'h3' ), true ) ? $heading : 'h2';
		$name = get_the_title( $p );
		$role = trim( (string) get_post_meta( $p->ID, 'staff_position', true ) );
		$cred = trim( (string) get_post_meta( $p->ID, 'staff_credentials', true ) );
		$bio  = trim( (string) $p->post_content );

		$icon_cap = '<svg class="bw-tm__cap" viewBox="0 0 24 24" role="img" aria-hidden="true" focusable="false">'
			. '<path d="M12 3 1 9l11 6 9-4.91V17h2V9L12 3zM5 13.18v3.82c0 .73 3.13 3 7 3s7-2.27 7-3v-3.82l-7 3.82-7-3.82z"/></svg>';
		$shield   = get_stylesheet_directory_uri() . '/blocks/team-modal/images/icon_gray.svg';

		// Feature layout (instructor inline variant): name + bio in a left column,
		// a full-height photo bleeding to the right edge. Distinct from the default
		// floated-photo profile used by the card/grid variants.
		if ( 'feature' === $layout ) {
			$f  = '<div class="bw-tm__profile bw-tm__profile--feature">';
			$f .= '<div class="bw-tm__feature-text">';
			$f .= '<span class="bw-tm__feature-curve" aria-hidden="true"></span>';
			$f .= '<' . $heading . ' class="bw-tm__p-name">' . esc_html( $name ) . '</' . $heading . '>';
			if ( '' !== $role ) {
				$f .= '<p class="bw-tm__p-role">' . esc_html( $role ) . '</p>';
			}
			if ( '' !== $cred ) {
				$f .= '<p class="bw-tm__p-cred">' . $icon_cap . '<span>' . esc_html( $cred ) . '</span></p>';
			}
			$f .= '<div class="bw-tm__p-bio">' . wp_kses_post( wpautop( $bio ) ) . '</div>';
			$f .= '</div>'; // .bw-tm__feature-text
			if ( has_post_thumbnail( $p ) ) {
				$f .= '<div class="bw-tm__feature-photo">'
					. get_the_post_thumbnail( $p, 'large', array( 'loading' => 'lazy' ) )
					. '</div>';
			}
			$f .= '</div>'; // .bw-tm__profile--feature
			return $f;
		}

		$out  = '<div class="bw-tm__profile">';
		$out .= '<' . $heading . ' class="bw-tm__p-name">' . esc_html( $name ) . '</' . $heading . '>';
		if ( '' !== $role ) {
			$out .= '<p class="bw-tm__p-role">' . esc_html( $role ) . '</p>';
		}
		if ( '' !== $cred ) {
			$out .= '<p class="bw-tm__p-cred">' . $icon_cap . '<span>' . esc_html( $cred ) . '</span></p>';
		}
		$out .= '<div class="bw-tm__p-content">';
		if ( has_post_thumbnail( $p ) ) {
			$out .= '<div class="bw-tm__p-photo">'
				// 'large', not 'medium': `medium` is only 225x300 for a 3:4 portrait
				// and visibly pixelates on 2x/3x displays.
				. get_the_post_thumbnail( $p, 'large', array( 'class' => 'bw-tm__p-img', 'loading' => 'lazy' ) )
				. '</div>';
		}
		$out .= '<div class="bw-tm__p-bio">' . wp_kses_post( wpautop( $bio ) ) . '</div>';
		$out .= '</div>';
		$out .= '<div class="bw-tm__footer"><span class="bw-tm__rule"></span>'
			. '<img class="bw-tm__shield" src="' . esc_url( $shield ) . '" alt="Brentwood Shield" /></div>';
		$out .= '</div>';

		return $out;
	}
}
