<?php
/**
 * Attendance tracking  -  unified engine for admin + teacher portal.
 *
 * Provides three views in a single panel so admins and teachers see the
 * same UI for taking attendance, reviewing past sessions by date, and
 * auditing per-student attendance history for a class.
 *
 * @package TradeSchoolManagerPro
 */

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

/*
 * Attendance owns wp_tsm_attendance_* custom tables. All $wpdb table
 * interpolation uses $wpdb->prefix + literal strings; values use $wpdb->prepare().
 */
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

class TSMP_Attendance {

	const STATUSES = array( 'present', 'absent', 'tardy', 'excused' );

	public static function table() {
		global $wpdb;
		return $wpdb->prefix . 'tsm_attendance';
	}

	/** Normalize legacy / synonym status codes (e.g. "late" -> "tardy"). */
	public static function normalize_status( $status ) {
		$status = strtolower( trim( (string) $status ) );
		if ( 'late' === $status ) { $status = 'tardy'; }
		return in_array( $status, self::STATUSES, true ) ? $status : 'present';
	}

	public static function status_label( $status ) {
		$map = array(
			'present' => __( 'Present', 'tradeschool-manager' ),
			'absent'  => __( 'Absent',  'tradeschool-manager' ),
			'tardy'   => __( 'Tardy',   'tradeschool-manager' ),
			'excused' => __( 'Excused', 'tradeschool-manager' ),
		);
		$status = self::normalize_status( $status );
		return $map[ $status ];
	}

	public static function set( $class_id, $student_id, $date, $status, $notes = '' ) {
		global $wpdb;
		$wpdb->replace(
			self::table(),
			array(
				'class_id'   => absint( $class_id ),
				'student_id' => absint( $student_id ),
				'date'       => sanitize_text_field( $date ),
				'status'     => self::normalize_status( $status ),
				'notes'      => sanitize_textarea_field( $notes ),
			)
		);
	}

	public static function for_class_date( $class_id, $date ) {
		global $wpdb;
		$t = self::table();
		return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$t} WHERE class_id = %d AND date = %s", absint( $class_id ), sanitize_text_field( $date ) ) );
	}

	public static function for_student( $student_id ) {
		global $wpdb;
		$t = self::table();
		return $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$t} WHERE student_id = %d ORDER BY date DESC LIMIT 200", absint( $student_id ) ) );
	}

	/** All marks for a single student in a single class, newest first. */
	public static function for_student_class( $student_id, $class_id ) {
		global $wpdb;
		$t = self::table();
		return $wpdb->get_results( $wpdb->prepare(
			"SELECT * FROM {$t} WHERE student_id = %d AND class_id = %d ORDER BY date DESC",
			absint( $student_id ), absint( $class_id )
		) );
	}

	/**
	 * Distinct dates that have attendance marks for a class, with per-date
	 * counts so the history view can show a quick summary at a glance.
	 *
	 * @return array<object{date:string,present:int,absent:int,tardy:int,excused:int,total:int}>
	 */
	public static function dates_for_class( $class_id, $limit = 180 ) {
		global $wpdb;
		$t = self::table();
		return $wpdb->get_results( $wpdb->prepare(
			"SELECT date,
				SUM(CASE WHEN status='present' THEN 1 ELSE 0 END) AS present,
				SUM(CASE WHEN status='absent'  THEN 1 ELSE 0 END) AS absent,
				SUM(CASE WHEN status IN ('tardy','late') THEN 1 ELSE 0 END) AS tardy,
				SUM(CASE WHEN status='excused' THEN 1 ELSE 0 END) AS excused,
				COUNT(*) AS total
			 FROM {$t}
			 WHERE class_id = %d
			 GROUP BY date
			 ORDER BY date DESC
			 LIMIT %d",
			absint( $class_id ), absint( $limit )
		) );
	}

	/**
	 * Per-student summary across all sessions of a class.
	 *
	 * @return array<int,array{present:int,absent:int,tardy:int,excused:int,total:int,rate:float}>
	 *         keyed by student_id.
	 */
	public static function summary_for_class( $class_id ) {
		global $wpdb;
		$t = self::table();
		$rows = $wpdb->get_results( $wpdb->prepare(
			"SELECT student_id,
				SUM(CASE WHEN status='present' THEN 1 ELSE 0 END) AS present,
				SUM(CASE WHEN status='absent'  THEN 1 ELSE 0 END) AS absent,
				SUM(CASE WHEN status IN ('tardy','late') THEN 1 ELSE 0 END) AS tardy,
				SUM(CASE WHEN status='excused' THEN 1 ELSE 0 END) AS excused,
				COUNT(*) AS total
			 FROM {$t}
			 WHERE class_id = %d
			 GROUP BY student_id",
			absint( $class_id )
		) );
		$out = array();
		foreach ( $rows as $r ) {
			$total = (int) $r->total;
			$counted = $total - (int) $r->excused; // excused absences don't hurt rate
			$rate = $counted > 0 ? round( ( ( (int) $r->present + (int) $r->tardy ) / $counted ) * 100, 1 ) : 0.0;
			$out[ (int) $r->student_id ] = array(
				'present' => (int) $r->present,
				'absent'  => (int) $r->absent,
				'tardy'   => (int) $r->tardy,
				'excused' => (int) $r->excused,
				'total'   => $total,
				'rate'    => $rate,
			);
		}
		return $out;
	}

	/* ===================================================================
	 * Admin entry-point (TradeSchool -> Attendance)
	 * =================================================================== */
	public static function render_admin() {
		$default_year = class_exists( 'TSM_Active_Year' ) ? (int) TSM_Active_Year::get() : 0;
		$year_id  = (int) $default_year; // Year is fixed by the global topbar switcher.
		$class_id = isset( $_GET['class_id'] ) ? absint( $_GET['class_id'] ) : 0; // phpcs:ignore

		// Save handler (admin Take view).
		if ( isset( $_POST['tsmp_attendance_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['tsmp_attendance_nonce'] ) ), 'tsmp_attendance' ) ) {
			$cid  = absint( $_POST['class_id'] ?? 0 );
			$d    = sanitize_text_field( wp_unslash( $_POST['date'] ?? '' ) );
			$rows = isset( $_POST['att'] ) ? (array) wp_unslash( $_POST['att'] ) : array(); // phpcs:ignore
			foreach ( $rows as $sid => $vals ) {
				self::set( $cid, absint( $sid ), $d, $vals['status'] ?? 'present', $vals['notes'] ?? '' );
			}
			echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Attendance saved.', 'tradeschool-manager' ) . '</p></div>';
			$class_id = $cid;
		}

		$classes = TSM_Classes::all( $year_id );
		if ( $class_id && $year_id ) {
			$valid = false;
			foreach ( $classes as $c ) { if ( (int) $c->id === $class_id ) { $valid = true; break; } }
			if ( ! $valid ) { $class_id = 0; }
		}
		?>
		<form method="get" class="tsm-attendance-filters" style="display:flex;gap:14px;align-items:flex-end;flex-wrap:wrap;margin:6px 0 16px;">
			<input type="hidden" name="page" value="tsm-attendance">
			<label style="display:flex;flex-direction:column;font-weight:600;font-size:12px;">
				<?php esc_html_e( 'Class', 'tradeschool-manager' ); ?>
				<select name="class_id" onchange="this.form.submit()" style="min-width:240px;">
					<option value="0"><?php esc_html_e( ' -  Select class  - ', 'tradeschool-manager' ); ?></option>
					<?php foreach ( $classes as $c ) : ?>
						<option value="<?php echo esc_attr( $c->id ); ?>" <?php selected( $class_id, $c->id ); ?>><?php echo esc_html( $c->name ); ?></option>
					<?php endforeach; ?>
				</select>
			</label>
		</form>

		<?php if ( ! $class_id ) : ?>
			<p class="description"><?php esc_html_e( 'Select a class to take or review attendance. Switch the active school year in the topbar to load a different year\'s classes.', 'tradeschool-manager' ); ?></p>
		<?php else :
			$tab  = isset( $_GET['att_tab'] ) ? sanitize_key( $_GET['att_tab'] ) : 'take'; // phpcs:ignore
			$date = isset( $_GET['date'] ) ? sanitize_text_field( wp_unslash( $_GET['date'] ) ) : current_time( 'Y-m-d' ); // phpcs:ignore
			$sid  = isset( $_GET['sid'] ) ? absint( $_GET['sid'] ) : 0; // phpcs:ignore
			$base = add_query_arg( array( 'page' => 'tsm-attendance', 'year_id' => $year_id, 'class_id' => $class_id ), admin_url( 'admin.php' ) );
			self::render_panel( array(
				'class_id'    => $class_id,
				'tab'         => $tab,
				'date'        => $date,
				'student_id'  => $sid,
				'base_url'    => $base,
				'admin'       => true,
				'save_method' => 'post', // posts back to current admin URL
			) );
		endif;
	}

	/* ===================================================================
	 * Unified panel  -  used by admin and teacher portal.
	 *
	 * @param array $args {
	 *   class_id    int    required
	 *   tab         string one of: take | history | by_student
	 *   date        string Y-m-d (used by take + history detail)
	 *   student_id  int    selected student (by_student tab)
	 *   base_url    string URL for tab links (without att_tab/date/sid)
	 *   admin       bool   true on admin screen (uses tsmp_attendance_nonce)
	 * }
	 * =================================================================== */
	public static function render_panel( $args ) {
		$class_id = absint( $args['class_id'] ?? 0 );
		if ( ! $class_id ) { return; }
		$tab      = in_array( $args['tab'] ?? 'take', array( 'take', 'history', 'by_student' ), true ) ? $args['tab'] : 'take';
		$date     = $args['date'] ?? current_time( 'Y-m-d' );
		$sid      = absint( $args['student_id'] ?? 0 );
		$base     = $args['base_url'] ?? '';
		$admin    = ! empty( $args['admin'] );
		$class    = TSM_Classes::get( $class_id );
		$students = TSM_Classes::students_in_class( $class_id );

		$tab_url = function( $t, $extra = array() ) use ( $base ) {
			return add_query_arg( array_merge( array( 'att_tab' => $t ), $extra ), $base );
		};

		self::render_styles();
		?>
		<div class="tsm-att-panel">
			<nav class="tsm-att-tabs" role="tablist" aria-label="<?php esc_attr_e( 'Attendance views', 'tradeschool-manager' ); ?>">
				<a class="tsm-att-tab <?php echo 'take' === $tab ? 'is-active' : ''; ?>" href="<?php echo esc_url( $tab_url( 'take', array( 'date' => $date ) ) ); ?>"><?php esc_html_e( 'Take Attendance', 'tradeschool-manager' ); ?></a>
				<a class="tsm-att-tab <?php echo 'history' === $tab ? 'is-active' : ''; ?>" href="<?php echo esc_url( $tab_url( 'history' ) ); ?>"><?php esc_html_e( 'Session History', 'tradeschool-manager' ); ?></a>
				<a class="tsm-att-tab <?php echo 'by_student' === $tab ? 'is-active' : ''; ?>" href="<?php echo esc_url( $tab_url( 'by_student' ) ); ?>"><?php esc_html_e( 'By Student', 'tradeschool-manager' ); ?></a>
			</nav>

			<?php
			if ( 'take' === $tab ) {
				self::view_take( $class, $students, $date, $admin );
			} elseif ( 'history' === $tab ) {
				self::view_history( $class, $students, $date, $admin, $tab_url );
			} else {
				self::view_by_student( $class, $students, $sid, $admin, $tab_url );
			}
			?>
		</div>
		<?php
	}

	/* -------------------------- Tab: Take -------------------------- */
	private static function view_take( $class, $students, $date, $admin ) {
		$existing = array();
		foreach ( self::for_class_date( $class->id, $date ) as $r ) {
			$existing[ (int) $r->student_id ] = $r;
		}
		?>
		<form method="get" class="tsm-att-datebar">
			<?php if ( $admin ) : ?>
				<input type="hidden" name="page" value="tsm-attendance">
				<input type="hidden" name="year_id" value="<?php echo esc_attr( (int) $class->school_year_id ); ?>">
				<input type="hidden" name="class_id" value="<?php echo esc_attr( (int) $class->id ); ?>">
			<?php else : ?>
				<input type="hidden" name="tsm_view" value="attendance">
				<input type="hidden" name="cid" value="<?php echo esc_attr( (int) $class->id ); ?>">
			<?php endif; ?>
			<input type="hidden" name="att_tab" value="take">
			<label><strong><?php esc_html_e( 'Session date', 'tradeschool-manager' ); ?>:</strong>
				<input type="date" name="date" value="<?php echo esc_attr( $date ); ?>">
			</label>
			<button class="button"><?php esc_html_e( 'Load', 'tradeschool-manager' ); ?></button>
			<span class="tsm-att-meta"><?php echo esc_html( count( $students ) ); ?> <?php esc_html_e( 'students', 'tradeschool-manager' ); ?> - <?php echo esc_html( $class->name ); ?></span>
		</form>

		<div class="tsm-att-bulk">
			<strong><?php esc_html_e( 'Mark all:', 'tradeschool-manager' ); ?></strong>
			<?php foreach ( self::STATUSES as $st ) : ?>
				<button type="button" class="button button-small tsm-att-bulk-btn" data-status="<?php echo esc_attr( $st ); ?>"><?php echo esc_html( self::status_label( $st ) ); ?></button>
			<?php endforeach; ?>
		</div>

		<form method="post" class="tsm-att-form">
			<?php if ( $admin ) {
				wp_nonce_field( 'tsmp_attendance', 'tsmp_attendance_nonce' );
			} else {
				wp_nonce_field( 'tsm_teacher_save_attendance' );
				echo '<input type="hidden" name="tsm_teacher_action" value="save_attendance">';
			} ?>
			<input type="hidden" name="class_id" value="<?php echo esc_attr( (int) $class->id ); ?>">
			<input type="hidden" name="date" value="<?php echo esc_attr( $date ); ?>">
			<input type="hidden" name="attendance_date" value="<?php echo esc_attr( $date ); ?>"><?php // teacher portal field name ?>

			<table class="tsm-att-grid tsm-stack-table widefat striped">
				<thead><tr>
					<th style="width:40px"></th>
					<th style="width:30%"><?php esc_html_e( 'Student', 'tradeschool-manager' ); ?></th>
					<th style="width:40%"><?php esc_html_e( 'Status', 'tradeschool-manager' ); ?></th>
					<th><?php esc_html_e( 'Notes', 'tradeschool-manager' ); ?></th>
				</tr></thead>
				<tbody>
				<?php if ( empty( $students ) ) : ?>
					<tr><td colspan="4"><em><?php esc_html_e( 'No students enrolled in this class.', 'tradeschool-manager' ); ?></em></td></tr>
				<?php endif; ?>
				<?php foreach ( $students as $s ) :
					$cur    = $existing[ (int) $s->id ] ?? null;
					$cur_st = self::normalize_status( $cur->status ?? 'present' );
					$initials = strtoupper( substr( $s->first_name, 0, 1 ) . substr( $s->last_name, 0, 1 ) ); ?>
					<tr>
						<td data-label="" style="width:40px;padding-right:0;">
							<?php if ( ! empty( $s->photo_url ) ) : ?>
								<img src="<?php echo esc_url( $s->photo_url ); ?>" alt="" style="width:28px;height:28px;border-radius:50%;object-fit:cover;display:block;border:1px solid var(--tsm-border,#e5e7eb);">
							<?php else : ?>
								<div aria-hidden="true" style="width:28px;height:28px;border-radius:50%;background:var(--tsm-brand,#1f6feb);color:#fff;font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center;line-height:1;"><?php echo esc_html( $initials ); ?></div>
							<?php endif; ?>
						</td>
						<td data-label="<?php esc_attr_e( 'Student', 'tradeschool-manager' ); ?>"><strong><?php echo esc_html( $s->last_name . ', ' . $s->first_name ); ?></strong></td>
						<td data-label="<?php esc_attr_e( 'Status', 'tradeschool-manager' ); ?>">
							<div class="tsm-att-pills" data-student="<?php echo esc_attr( $s->id ); ?>">
								<?php foreach ( self::STATUSES as $st ) : ?>
									<label class="tsm-att-pill <?php echo $cur_st === $st ? 'is-active att-' . esc_attr( $st ) : ''; ?>">
										<input type="radio" name="att[<?php echo esc_attr( $s->id ); ?>][status]" value="<?php echo esc_attr( $st ); ?>" <?php checked( $cur_st, $st ); ?>>
										<?php // Teacher-portal save handler reads attendance[sid]; mirror it. ?>
										<input type="hidden" disabled>
										<span><?php echo esc_html( self::status_label( $st ) ); ?></span>
									</label>
								<?php endforeach; ?>
							</div>
							<?php // mirror selection into teacher-portal field name as well ?>
							<input type="hidden" name="attendance[<?php echo esc_attr( $s->id ); ?>]" value="<?php echo esc_attr( $cur_st ); ?>" data-att-mirror="<?php echo esc_attr( $s->id ); ?>">
						</td>
						<td data-label="<?php esc_attr_e( 'Notes', 'tradeschool-manager' ); ?>"><input class="regular-text" name="att[<?php echo esc_attr( $s->id ); ?>][notes]" value="<?php echo esc_attr( $cur->notes ?? '' ); ?>" placeholder="<?php esc_attr_e( 'Optional', 'tradeschool-manager' ); ?>" style="width:100%"></td>
					</tr>
				<?php endforeach; ?>
				</tbody>
			</table>
			<div class="tsm-save-bar"><button class="button button-primary button-large tsm-att-save"><?php esc_html_e( 'Save Attendance', 'tradeschool-manager' ); ?></button></div>
		</form>
		<?php
		self::print_take_script();
	}

	/* -------------------------- Tab: Session History -------------------------- */
	private static function view_history( $class, $students, $date, $admin, $tab_url ) {
		$dates = self::dates_for_class( $class->id );
		// If a date is selected (or defaulted) and exists in the list, show its detail.
		$detail_date = $date;
		$has_detail  = false;
		foreach ( $dates as $d ) { if ( $d->date === $detail_date ) { $has_detail = true; break; } }
		?>
		<div class="tsm-att-history <?php echo $admin ? '' : 'is-stacked'; ?>">
			<div class="tsm-att-history-list">
				<h4><?php esc_html_e( 'Past sessions', 'tradeschool-manager' ); ?></h4>
				<?php if ( empty( $dates ) ) : ?>
					<p><em><?php esc_html_e( 'No attendance has been recorded for this class yet.', 'tradeschool-manager' ); ?></em></p>
				<?php else : ?>
					<table class="widefat striped tsm-att-sessions">
						<thead><tr>
							<th><?php esc_html_e( 'Date', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Present', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Absent', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Tardy', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Excused', 'tradeschool-manager' ); ?></th>
							<th></th>
						</tr></thead>
						<tbody>
						<?php foreach ( $dates as $d ) :
							$is_active = ( $d->date === $detail_date ); ?>
							<tr class="<?php echo $is_active ? 'is-active-row' : ''; ?>">
								<td><strong><?php echo esc_html( mysql2date( get_option( 'date_format', 'Y-m-d' ), $d->date ) ); ?></strong><br><span class="description"><?php echo esc_html( $d->date ); ?></span></td>
								<td><span class="tsm-att-chip att-present"><?php echo (int) $d->present; ?></span></td>
								<td><span class="tsm-att-chip att-absent"><?php echo (int) $d->absent; ?></span></td>
								<td><span class="tsm-att-chip att-tardy"><?php echo (int) $d->tardy; ?></span></td>
								<td><span class="tsm-att-chip att-excused"><?php echo (int) $d->excused; ?></span></td>
								<td><a class="button button-small" href="<?php echo esc_url( $tab_url( 'history', array( 'date' => $d->date ) ) ); ?>"><?php esc_html_e( 'View', 'tradeschool-manager' ); ?></a>
								<?php if ( $admin ) : ?>
									<a class="button button-small" href="<?php echo esc_url( $tab_url( 'take', array( 'date' => $d->date ) ) ); ?>"><?php esc_html_e( 'Edit', 'tradeschool-manager' ); ?></a>
								<?php endif; ?>
								</td>
							</tr>
						<?php endforeach; ?>
						</tbody>
					</table>
				<?php endif; ?>
			</div>

			<?php if ( $has_detail && $admin ) :
				$marks = array();
				foreach ( self::for_class_date( $class->id, $detail_date ) as $r ) { $marks[ (int) $r->student_id ] = $r; }
				?>
				<div class="tsm-att-history-detail">
					<h4><?php /* translators: placeholder(s) for dynamic value(s). */ printf( esc_html__( 'Roster  -  %s', 'tradeschool-manager' ), esc_html( mysql2date( get_option( 'date_format', 'Y-m-d' ), $detail_date ) ) ); ?></h4>
					<table class="widefat striped">
						<thead><tr>
							<th><?php esc_html_e( 'Student', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Status', 'tradeschool-manager' ); ?></th>
							<th><?php esc_html_e( 'Notes', 'tradeschool-manager' ); ?></th>
						</tr></thead>
						<tbody>
						<?php foreach ( $students as $s ) :
							$m  = $marks[ (int) $s->id ] ?? null;
							$st = $m ? self::normalize_status( $m->status ) : null; ?>
							<tr>
								<td><?php echo esc_html( $s->last_name . ', ' . $s->first_name ); ?></td>
								<td>
									<?php if ( $st ) : ?>
										<span class="tsm-att-chip att-<?php echo esc_attr( $st ); ?>"><?php echo esc_html( self::status_label( $st ) ); ?></span>
									<?php else : ?>
										<span class="tsm-att-chip att-none"><?php esc_html_e( 'Not marked', 'tradeschool-manager' ); ?></span>
									<?php endif; ?>
								</td>
								<td><?php echo esc_html( $m->notes ?? '' ); ?></td>
							</tr>
						<?php endforeach; ?>
						</tbody>
					</table>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	/* -------------------------- Tab: By Student -------------------------- */
	private static function view_by_student( $class, $students, $sid, $admin, $tab_url ) {
		$summary = self::summary_for_class( $class->id );
		?>
		<div class="tsm-att-by-student <?php echo $admin ? '' : 'is-stacked'; ?>">
			<div class="tsm-att-roster">
				<h4><?php esc_html_e( 'Class roster', 'tradeschool-manager' ); ?></h4>
				<table class="widefat striped">
					<thead><tr>
						<th><?php esc_html_e( 'Student', 'tradeschool-manager' ); ?></th>
						<th><?php esc_html_e( 'P', 'tradeschool-manager' ); ?></th>
						<th><?php esc_html_e( 'A', 'tradeschool-manager' ); ?></th>
						<th><?php esc_html_e( 'T', 'tradeschool-manager' ); ?></th>
						<th><?php esc_html_e( 'E', 'tradeschool-manager' ); ?></th>
						<th><?php esc_html_e( 'Rate', 'tradeschool-manager' ); ?></th>
						<th></th>
					</tr></thead>
					<tbody>
					<?php foreach ( $students as $s ) :
						$row = $summary[ (int) $s->id ] ?? array( 'present' => 0, 'absent' => 0, 'tardy' => 0, 'excused' => 0, 'total' => 0, 'rate' => 0 );
						$is_active = ( (int) $s->id === $sid ); ?>
						<tr class="<?php echo $is_active ? 'is-active-row' : ''; ?>">
							<td><strong><?php echo esc_html( $s->last_name . ', ' . $s->first_name ); ?></strong></td>
							<td><?php echo (int) $row['present']; ?></td>
							<td><?php echo (int) $row['absent']; ?></td>
							<td><?php echo (int) $row['tardy']; ?></td>
							<td><?php echo (int) $row['excused']; ?></td>
							<td><?php echo $row['total'] ? esc_html( $row['rate'] . '%' ) : ' - '; ?></td>
							<td><a class="button button-small" href="<?php echo esc_url( $tab_url( 'by_student', array( 'sid' => $s->id ) ) ); ?>"><?php esc_html_e( 'History', 'tradeschool-manager' ); ?></a></td>
						</tr>
					<?php endforeach; ?>
					</tbody>
				</table>
			</div>

			<?php if ( $sid ) :
				$student = null;
				foreach ( $students as $s ) { if ( (int) $s->id === $sid ) { $student = $s; break; } }
				if ( $student ) :
					$rows = self::for_student_class( $sid, $class->id ); ?>
					<div class="tsm-att-student-detail">
						<h4><?php echo esc_html( $student->first_name . ' ' . $student->last_name ); ?>  -  <?php esc_html_e( 'Attendance history', 'tradeschool-manager' ); ?></h4>
						<?php if ( empty( $rows ) ) : ?>
							<p><em><?php esc_html_e( 'No attendance records for this student in this class.', 'tradeschool-manager' ); ?></em></p>
						<?php else : ?>
							<table class="widefat striped">
								<thead><tr>
									<th><?php esc_html_e( 'Date', 'tradeschool-manager' ); ?></th>
									<th><?php esc_html_e( 'Status', 'tradeschool-manager' ); ?></th>
									<th><?php esc_html_e( 'Notes', 'tradeschool-manager' ); ?></th>
								</tr></thead>
								<tbody>
								<?php foreach ( $rows as $r ) :
									$st = self::normalize_status( $r->status ); ?>
									<tr>
										<td><?php echo esc_html( mysql2date( get_option( 'date_format', 'Y-m-d' ), $r->date ) ); ?></td>
										<td><span class="tsm-att-chip att-<?php echo esc_attr( $st ); ?>"><?php echo esc_html( self::status_label( $st ) ); ?></span></td>
										<td><?php echo esc_html( $r->notes ); ?></td>
									</tr>
								<?php endforeach; ?>
								</tbody>
							</table>
						<?php endif; ?>
					</div>
				<?php endif;
			endif; ?>
		</div>
		<?php
	}

	/* -------------------------- Shared styles -------------------------- */
	private static function render_styles() {
		static $printed = false;
		if ( $printed ) { return; }
		$printed = true;

		$handle = 'tsm-attendance';
		wp_register_style( $handle, false, array(), defined( 'TSM_VERSION' ) ? TSM_VERSION : '1' );
		wp_enqueue_style( $handle );
		wp_add_inline_style(
			$handle,
			'.tsm-att-panel{--att-present:#16a34a;--att-absent:#dc2626;--att-tardy:#d97706;--att-excused:#6366f1;--att-none:#9ca3af}'
			. '.tsm-att-tabs{display:flex;gap:4px;border-bottom:1px solid #d1d5db;margin:8px 0 16px}'
			. '.tsm-att-tab{padding:8px 14px;text-decoration:none;color:#374151;font-weight:600;border:1px solid transparent;border-bottom:none;border-radius:6px 6px 0 0}'
			. '.tsm-att-tab.is-active{background:#fff;border-color:#d1d5db;color:#111827}'
			. '.tsm-att-datebar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:6px 0 12px}'
			. '.tsm-att-meta{color:#6b7280;font-size:13px}'
			. '.tsm-att-bulk{display:flex;gap:8px;align-items:center;margin:6px 0 12px;flex-wrap:wrap}'
			. '.tsm-att-pills{display:inline-flex;gap:4px;flex-wrap:wrap}'
			. '.tsm-att-pill{display:inline-flex;align-items:center;padding:4px 10px;border:1px solid #d1d5db;border-radius:999px;font-size:12px;font-weight:600;cursor:pointer;background:#f9fafb;color:#374151;user-select:none}'
			. '.tsm-att-pill input{position:absolute;opacity:0;width:0;height:0}'
			. '.tsm-att-pill.is-active{color:#fff;border-color:transparent}'
			. '.tsm-att-pill.att-present.is-active{background:var(--att-present)}'
			. '.tsm-att-pill.att-absent.is-active{background:var(--att-absent)}'
			. '.tsm-att-pill.att-tardy.is-active{background:var(--att-tardy)}'
			. '.tsm-att-pill.att-excused.is-active{background:var(--att-excused)}'
			. '.tsm-att-chip{display:inline-block;padding:2px 8px;border-radius:999px;font-size:11px;font-weight:700;color:#fff;min-width:24px;text-align:center}'
			. '.tsm-att-chip.att-present{background:var(--att-present)}'
			. '.tsm-att-chip.att-absent{background:var(--att-absent)}'
			. '.tsm-att-chip.att-tardy{background:var(--att-tardy)}'
			. '.tsm-att-chip.att-excused{background:var(--att-excused)}'
			. '.tsm-att-chip.att-none{background:var(--att-none)}'
			. '.tsm-att-history,.tsm-att-by-student{display:grid;grid-template-columns:1fr;gap:18px}'
			. '@media(min-width:1100px){.tsm-att-history,.tsm-att-by-student{grid-template-columns:1.2fr 1fr}}'
			. '.tsm-att-history.is-stacked,.tsm-att-by-student.is-stacked{grid-template-columns:1fr !important}'
			. '.is-active-row{background:#eef2ff !important}'
			. '.tsm-att-sessions th,.tsm-att-sessions td{vertical-align:middle}'
		);
		wp_print_styles( array( $handle ) );
	}

	private static function print_take_script() {
		static $printed = false;
		if ( $printed ) { return; }
		$printed = true;

		$handle = 'tsm-attendance';
		wp_register_script( $handle, false, array(), defined( 'TSM_VERSION' ) ? TSM_VERSION : '1', true );
		wp_enqueue_script( $handle );
		wp_add_inline_script(
			$handle,
			"(function(){\n"
			. "\tfunction syncMirror(grp){\n"
			. "\t\tvar checked = grp.querySelector('input[type=radio]:checked');\n"
			. "\t\tvar sid = grp.getAttribute('data-student');\n"
			. "\t\tvar mirror = document.querySelector('input[data-att-mirror=\"' + sid + '\"]');\n"
			. "\t\tif (mirror && checked) { mirror.value = checked.value; }\n"
			. "\t}\n"
			. "\tdocument.querySelectorAll('.tsm-att-bulk-btn').forEach(function(btn){\n"
			. "\t\tbtn.addEventListener('click', function(){\n"
			. "\t\t\tvar st = btn.getAttribute('data-status');\n"
			. "\t\t\tdocument.querySelectorAll('.tsm-att-pills').forEach(function(grp){\n"
			. "\t\t\t\tgrp.querySelectorAll('input[type=radio]').forEach(function(r){\n"
			. "\t\t\t\t\tif (r.value === st) { r.checked = true; r.dispatchEvent(new Event('change', {bubbles:true})); }\n"
			. "\t\t\t\t});\n"
			. "\t\t\t});\n"
			. "\t\t});\n"
			. "\t});\n"
			. "\tdocument.querySelectorAll('.tsm-att-pills').forEach(function(grp){\n"
			. "\t\tgrp.addEventListener('change', function(){\n"
			. "\t\t\tgrp.querySelectorAll('.tsm-att-pill').forEach(function(p){ p.classList.remove('is-active','att-present','att-absent','att-tardy','att-excused'); });\n"
			. "\t\t\tvar checked = grp.querySelector('input[type=radio]:checked');\n"
			. "\t\t\tif (checked) { checked.closest('.tsm-att-pill').classList.add('is-active','att-' + checked.value); }\n"
			. "\t\t\tsyncMirror(grp);\n"
			. "\t\t});\n"
			. "\t\tsyncMirror(grp);\n"
			. "\t});\n"
			. "})();\n"
		);
		wp_print_scripts( array( $handle ) );
	}
}
