/**
 * Student Dashboard (student)
 *
 * Phase 3 Recharts + Phase 2 endpoints:
 *   - Average per-class BarChart  (per_course.average)
 *   - Attendance trend LineChart (attendanceByDay)
 *   - Upcoming Deadlines list (fetchStudentUpcomingDeadlines)
 *   - KPI tiles + leaderboard badge (kept)
 *
 * PR 3 §13 follow-up — also surfaces a "Marked scripts available" callout
 * fed by the shared realtime store (see store/realtime.ts). Updates within
 * seconds of the teacher clicking "Return" on the grade-book.
 *
 * Accessibility (NFR6): every interactive element is a real <Link> /
 * <button> (not a clickable <div>); decorative icons are aria-hidden;
 * charts expose a visually-hidden <table> alternative; live regions
 * announce dynamic counts (marked-scripts) without interrupting other
 * speech; heading hierarchy is monotonic (h1 → h2 → h3).
 */

import { useEffect, useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import {
  AlertCircle, ShieldX, RefreshCw, Trophy, CheckCircle2, BookOpen,
  Calendar, Clock, FileText, DollarSign, GraduationCap, Award,
  AlertTriangle, CalendarClock, FileCheck, ChevronRight,
} from 'lucide-react';
import {
  BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip,
  ResponsiveContainer, Cell, LineChart, Line, ReferenceLine,
} from 'recharts';
import { useDashboardStore } from '../../store/dashboard';
import { useRealtimeStore } from '../../store/realtime';
import { useEducationTerms } from '../../utils/educationTerms';
import api from '../../store/api';

// KPI tile status words — make colour-only status accessible to SR users.
// Maps the kpi.color we render into a one-word tone for the aria-label.
const KPI_TONE_LABEL: Record<string, string> = {
  emerald: 'on track',
  orange: 'needs attention',
  red: 'urgent',
  blue: '',
  purple: '',
};

export default function StudentDashboard() {
  const navigate = useNavigate();
  const terms = useEducationTerms();
  const {
    student, loading, error, accessDenied, fetchStudent,
    studentUpcomingDeadlines, fetchStudentUpcomingDeadlines,
  } = useDashboardStore();

  // PR 3 §13 follow-up — pull count + latest from the shared realtime store
  // (counts are bumped on every server broadcast; see store/realtime.ts).
  const realtimeMarkedCount = useRealtimeStore(s => s.markedScriptReturnCount);
  const realtimeMarkedLatest = useRealtimeStore(s => s.latestMarkedScript);

  // PR 3 §6.4 — also fetch the student's own submissions on mount so the
  // callout can surface a count even before any realtime events fire.
  const [markedScriptCount, setMarkedScriptCount] = useState(0);
  const [recentMarkedScript, setRecentMarkedScript] = useState<any | null>(null);

  useEffect(() => {
    fetchStudent();
    fetchStudentUpcomingDeadlines();
    api.get('/assignments/my/submissions')
      .then(res => {
        const rows: any[] = Array.isArray(res.data) ? res.data : [];
        const returnedWithScripts = rows.filter(s =>
          s.status === 'returned' && Array.isArray(s.marked_scripts) && s.marked_scripts.length > 0
        );
        setMarkedScriptCount(returnedWithScripts.length);
        if (returnedWithScripts.length > 0) {
          returnedWithScripts.sort((a, b) => {
            const at = a.graded_at || a.submitted_at || '';
            const bt = b.graded_at || b.submitted_at || '';
            return bt.localeCompare(at);
          });
          setRecentMarkedScript(returnedWithScripts[0]);
        }
      })
      .catch(err => console.warn('Could not load marked-scripts summary:', err?.response?.status || err?.message));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const totalMarkedCount = markedScriptCount + realtimeMarkedCount;
  const recentForCallout = recentMarkedScript ?? realtimeMarkedLatest?.data ?? null;

  if (loading && !student) {
    return (
      <div className="flex flex-col justify-center items-center h-[60vh] gap-4" role="status" aria-live="polite">
        <div className="w-12 h-12 border-4 border-blue-600 border-t-transparent rounded-full animate-spin" aria-hidden="true" />
        <p className="text-text-muted font-medium animate-pulse">Loading student dashboard&hellip;</p>
      </div>
    );
  }
  if (accessDenied) {
    return (
      <div className="flex flex-col justify-center items-center h-[60vh] gap-4" role="alert">
        <ShieldX size={56} className="text-red-500" aria-hidden="true" />
        <h2 className="text-2xl font-extrabold text-text">Access denied</h2>
        <p className="text-text-muted text-sm max-w-md text-center">
          {error || 'You do not have permission to view the student dashboard.'}
        </p>
        <button onClick={() => navigate('/dashboard/student')} className="px-4 py-2 bg-primary text-white rounded-xl hover:opacity-90">Go back</button>
      </div>
    );
  }
  if (error && !student) {
    return (
      <div className="flex flex-col justify-center items-center h-[60vh] gap-4" role="alert">
        <AlertCircle size={48} className="text-red-500" aria-hidden="true" />
        <p className="text-text-muted font-medium">Unable to load dashboard data.</p>
        <p className="text-sm text-text-muted">{error}</p>
        <button onClick={() => { fetchStudent(); fetchStudentUpcomingDeadlines(); }}
          className="flex items-center gap-2 px-4 py-2 bg-primary text-white rounded-xl">
          <RefreshCw size={16} aria-hidden="true" /> Retry
        </button>
      </div>
    );
  }
  if (!student) return null;

  const courseCount = student.per_course?.length || 0;
  const gradedCourses = (student.per_course || []).filter((c) => c.average != null).length;
  const overallAverage = gradedCourses > 0
    ? Math.round(
        ((student.per_course || [])
          .filter((c) => c.average != null)
          .reduce((sum, c) => sum + (c.average as number), 0) /
          gradedCourses) * 10,
      ) / 10
    : null;

  const rank = student.leaderboard_rank;
  const total = student.leaderboard_total_students;
  const rankPercentile = rank != null && total > 0 ? Math.round(((total - rank) / total) * 100) : null;
  const rankBadge =
    rank == null ? { label: 'Not ranked', color: 'slate' as const }
    : rankPercentile != null && rankPercentile >= 90 ? { label: 'Top 10%', color: 'emerald' as const }
    : rankPercentile != null && rankPercentile >= 75 ? { label: 'Top 25%', color: 'blue' as const }
    : rankPercentile != null && rankPercentile >= 50 ? { label: 'Above Median', color: 'indigo' as const }
    : { label: 'Keep Going', color: 'orange' as const };

  const pendingCount = studentUpcomingDeadlines.length || student.pending_assignments_count;
  const kpis = [
    {
      label: 'Attendance',
      value: `${student.attendancePercent}%`,
      icon: CheckCircle2,
      color: student.attendancePercent >= 75 ? 'emerald' : 'orange',
      path: '/attendance',
      tone: student.attendancePercent >= 75 ? 'on track' : 'below 75% threshold',
    },
    {
      label: 'Active Classes',
      value: student.activeClasses,
      icon: BookOpen,
      color: 'blue',
      path: '/my-courses',
      tone: '',
    },
    {
      label: 'Pending (14d)',
      value: pendingCount,
      icon: FileText,
      color: pendingCount > 0 ? 'red' : 'emerald',
      path: '/assignments',
      tone: pendingCount > 0 ? 'urgent' : 'none outstanding',
    },
    {
      label: 'Points',
      value: student.gamification_points.toLocaleString(),
      icon: Trophy,
      color: 'purple',
      path: '/extracurriculars',
      tone: '',
    },
  ];

  // Per-course / per-subject average bar chart data. The internal
  // `average` key replaces the previous `gpa` label — Zim grading is
  // expressed as a percentage and a letter symbol, not GPA.
  const gpaChartData = (student.per_course || []).map((c) => ({
    course: c.course_name.length > 14 ? `${c.course_name.slice(0, 12)}…` : c.course_name,
    fullName: c.course_name,
    average: c.average ?? 0,
    fill: c.average == null ? '#94a3b8' : c.average >= 70 ? '#10b981' : c.average >= 50 ? '#f59e0b' : '#ef4444',
  }));

  // Attendance trend (last 5 school days)
  const attendanceTrend = (student.attendanceByDay || []).slice(0, 5).reverse().map((a) => ({
    date: a.date ? String(a.date).slice(5) : '',
    percent: a.present ?? 0,
  }));

  const urgentDeadlines = studentUpcomingDeadlines.filter((d) => d.urgency === 'urgent');
  const soonDeadlines = studentUpcomingDeadlines.filter((d) => d.urgency === 'soon');

  return (
    <div className="space-y-8 animate-in fade-in duration-500 pb-10">
      <div className="flex flex-col md:flex-row md:items-end justify-between gap-4">
        <div>
          <h1 id="student-dashboard-heading" className="text-3xl font-extrabold text-text tracking-tight">Student Dashboard</h1>
          <p className="text-text-muted mt-1 text-lg">Your courses, grades, and what&apos;s next.</p>
        </div>
        <button
          onClick={() => { fetchStudent(); fetchStudentUpcomingDeadlines(); }}
          className="flex items-center gap-2 px-4 py-2 bg-card border border-border text-text rounded-xl text-sm font-semibold hover:border-primary hover:text-primary transition-all"
          aria-label="Refresh dashboard data"
        >
          <RefreshCw size={16} aria-hidden="true" /> Refresh
        </button>
      </div>

      <section
        aria-labelledby="class-position-heading"
        className="bg-gradient-to-br from-primary to-[#002147] text-white rounded-2xl p-6 shadow-lg shadow-blue-900/10 flex items-center justify-between gap-4"
      >
        <div className="flex items-center gap-4">
          <div className="w-14 h-14 rounded-2xl bg-white/10 flex items-center justify-center border border-white/20" aria-hidden="true">
            <Award size={28} />
          </div>
          <div>
            <p className="text-[0.6rem] font-black uppercase tracking-[3px] text-white/50">Class Position</p>
            <h2 id="class-position-heading" className="text-2xl font-black tracking-tight">
              {rank != null ? `Position ${rank}` : 'Not yet ranked'}
              {total > 0 && rank != null && (
                <span className="text-sm font-medium text-white/60 ml-2">of {total.toLocaleString()} students</span>
              )}
            </h2>
            {rank != null && rankPercentile != null ? (
              <p className="text-sm text-white/80 mt-1">
                Top {100 - rankPercentile}% • {student.gamification_points.toLocaleString()} points earned
              </p>
            ) : (
              <p className="text-sm text-white/70 mt-1">
                Play a crossword or complete an activity to earn your first points and join the class position.
              </p>
            )}
          </div>
        </div>
        <span
          className={`px-4 py-2 rounded-full text-xs font-black uppercase tracking-widest border ${
            rankBadge.color === 'emerald' ? 'bg-emerald-500/20 text-emerald-300 border-emerald-300/30'
            : rankBadge.color === 'blue' ? 'bg-blue-500/20 text-blue-300 border-blue-300/30'
            : rankBadge.color === 'indigo' ? 'bg-indigo-500/20 text-indigo-300 border-indigo-300/30'
            : rankBadge.color === 'slate' ? 'bg-white/10 text-white/70 border-white/20'
            : 'bg-orange-500/20 text-orange-300 border-orange-300/30'
          }`}
          aria-label={`Rank band: ${rankBadge.label}`}
        >
          {rankBadge.label}
        </span>
      </section>

      {/* PR 3 §6.4 — marked-scripts callout. Counts merge the initial
          /my/submissions fetch with any realtime-incremented value from
          the shared useRealtimeStore. Renders above the KPI grid. */}
      {totalMarkedCount > 0 && (
        <Link
          to="/assignments"
          className="block bg-emerald-50 border border-emerald-200 dark:bg-emerald-500/10 dark:border-emerald-500/30 rounded-2xl p-6 flex flex-col sm:flex-row items-start sm:items-center gap-4 hover:shadow-lg hover:border-emerald-300 transition-all group focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-emerald-500 focus-visible:ring-offset-2"
          aria-label={`Open assignments: ${totalMarkedCount === 1 ? '1 marked script' : `${totalMarkedCount} marked scripts`} available`}
        >
          <div className="w-14 h-14 rounded-2xl bg-card border border-emerald-100 dark:border-emerald-500/30 flex items-center justify-center text-emerald-600 shrink-0 shadow-sm group-hover:scale-105 transition-transform" aria-hidden="true">
            <FileCheck size={26} />
          </div>
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-2 mb-1">
              <span className="text-[0.6rem] font-black uppercase tracking-[3px] text-emerald-700 dark:text-emerald-400">Marked Scripts Available</span>
              {/* aria-live=polite on the count specifically: WebSocket
                  increments are announced without re-announcing the
                  surrounding copy. */}
              <span
                className="inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded-full bg-emerald-600 text-white text-[0.65rem] font-black"
                aria-label={`${totalMarkedCount} marked script${totalMarkedCount === 1 ? '' : 's'}`}
                aria-live="polite"
              >
                <span aria-hidden="true">{totalMarkedCount}</span>
              </span>
            </div>
            <h3 className="text-lg font-black text-text tracking-tight">
              {totalMarkedCount === 1
                ? 'Your teacher has returned a marked script.'
                : `Your teacher has returned ${totalMarkedCount} marked scripts.`}
            </h3>
            {recentForCallout?.assignment_title && (
              <p className="text-sm text-text-muted mt-1 font-medium">
                Latest: <span className="font-bold text-text">{recentForCallout.assignment_title}</span>
                {recentForCallout.marked_scripts?.[0]?.uploaded_at && (
                  <span className="text-text-muted/70"> · returned {new Date(recentForCallout.marked_scripts[0].uploaded_at).toLocaleDateString()}</span>
                )}
              </p>
            )}
          </div>
          <div className="flex items-center gap-2 text-emerald-700 dark:text-emerald-400 font-black text-xs uppercase tracking-widest group-hover:translate-x-1 transition-transform">
            Open Assignments
            <ChevronRight size={18} aria-hidden="true" />
          </div>
        </Link>
      )}

      <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
        {kpis.map((kpi) => {
          const tone = KPI_TONE_LABEL[kpi.color] ?? '';
          const ariaLabel = tone
            ? `${kpi.label}: ${kpi.value} (${tone})`
            : `${kpi.label}: ${kpi.value}`;
          return (
            <Link
              key={kpi.label}
              to={kpi.path}
              aria-label={ariaLabel}
              className="bg-card p-5 rounded-2xl border border-border flex items-center gap-4 hover:shadow-md transition-all group focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2"
            >
              <div
                className={`w-12 h-12 rounded-2xl flex items-center justify-center border group-hover:scale-110 transition-transform ${
                  kpi.color === 'emerald' ? 'bg-emerald-50 dark:bg-emerald-900/20 text-emerald-600 dark:text-emerald-400 border-emerald-100 dark:border-emerald-900/30'
                  : kpi.color === 'blue' ? 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 border-blue-100 dark:border-blue-900/30'
                  : kpi.color === 'purple' ? 'bg-purple-50 dark:bg-purple-900/20 text-purple-600 dark:text-purple-400 border-purple-100 dark:border-purple-900/30'
                  : kpi.color === 'red' ? 'bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 border-red-100 dark:border-red-900/30'
                  : 'bg-orange-50 dark:bg-orange-900/20 text-orange-600 dark:text-orange-400 border-orange-100 dark:border-orange-900/30'
                }`}
                aria-hidden="true"
              >
                <kpi.icon size={22} />
              </div>
              <div>
                <p className="text-[0.65rem] font-black uppercase tracking-wider text-text-muted">{kpi.label}</p>
                <p className="text-2xl font-black text-text">{kpi.value}</p>
              </div>
            </Link>
          );
        })}
      </div>

      {/* Charts row */}
      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
        {/* Average per-course BarChart — Zim uses percentage + letter
            symbol, so the chart key is `average` (renamed from `gpa`)
            and the heading reads "Average by Subject". */}
        <figure className="bg-card rounded-2xl border border-border overflow-hidden shadow-sm">
          <figcaption className="px-6 py-4 border-b border-border bg-muted/50 flex items-center gap-2">
            <GraduationCap size={14} className="text-primary" aria-hidden="true" />
            <h3 className="text-[0.65rem] font-black uppercase tracking-[2px] text-primary">Average by {terms.subject}</h3>
            <span className="ml-auto text-[0.7rem] font-bold text-text-muted">
              {overallAverage != null ? `Overall ${overallAverage}%` : 'No grades'}
            </span>
          </figcaption>
          <div className="p-4">
            {gpaChartData.length === 0 ? (
              <p className="py-10 text-center text-text-muted text-sm">No courses yet.</p>
            ) : (
              <>
                <div
                  className="h-64 w-full"
                  role="img"
                  aria-label={`Bar chart of average percentage by subject. Overall ${overallAverage ?? '—'}%. Pass mark is 50%.`}
                >
                  <ResponsiveContainer width="100%" height="100%">
                    <BarChart data={gpaChartData} margin={{ top: 10, right: 10, left: 0, bottom: 30 }}>
                      <CartesianGrid strokeDasharray="3 3" stroke="rgba(148,163,184,0.2)" />
                      <XAxis dataKey="course" tick={{ fill: 'currentColor', fontSize: 10 }} angle={-25} textAnchor="end" interval={0} />
                      <YAxis domain={[0, 100]} tick={{ fill: 'currentColor', fontSize: 10 }} unit="%" />
                      <Tooltip
                        cursor={{ fill: 'currentColor', className: 'text-muted/10' }}
                        contentStyle={{ backgroundColor: 'var(--card)', border: '1px solid var(--border)', borderRadius: 12, color: 'var(--text)' }}
                        labelStyle={{ color: 'var(--text-light)', fontWeight: 700 }}
                        formatter={(v: number, _n: string, p: any) => [`${v}%`, p?.payload?.fullName || 'Average']}
                      />
                      <ReferenceLine y={50} stroke="#ef4444" strokeDasharray="3 3" label={{ value: 'Pass', fontSize: 10, fill: '#ef4444' }} />
                      <Bar dataKey="average" radius={[8, 8, 0, 0]}>
                        {gpaChartData.map((e, i) => <Cell key={i} fill={e.fill} />)}
                      </Bar>
                    </BarChart>
                  </ResponsiveContainer>
                </div>
                <table className="sr-only">
                  <caption>Average percentage by subject (pass mark 50%).</caption>
                  <thead>
                    <tr><th scope="col">Subject</th><th scope="col">Average</th></tr>
                  </thead>
                  <tbody>
                    {gpaChartData.map((c) => (
                      <tr key={c.course}>
                        <th scope="row">{c.fullName}</th>
                        <td>{c.average}%{c.average != null && c.average < 50 ? ' (below pass mark)' : ''}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </>
            )}
          </div>
        </figure>

        {/* Attendance trend LineChart */}
        <figure className="bg-card rounded-2xl border border-border overflow-hidden shadow-sm">
          <figcaption className="px-6 py-4 border-b border-border bg-muted/50 flex items-center gap-2">
            <CheckCircle2 size={14} className="text-primary" aria-hidden="true" />
            <h3 className="text-[0.65rem] font-black uppercase tracking-[2px] text-primary">Attendance (5 days)</h3>
            <span className="ml-auto text-[0.7rem] font-bold text-text-muted">
              {student.attendancePercent}%
            </span>
          </figcaption>
          <div className="p-4">
            {attendanceTrend.length === 0 ? (
              <p className="py-10 text-center text-text-muted text-sm">No recent attendance.</p>
            ) : (
              <>
                <div
                  className="h-64 w-full"
                  role="img"
                  aria-label={`Line chart of attendance over the last 5 school days. Overall ${student.attendancePercent}%.`}
                >
                  <ResponsiveContainer width="100%" height="100%">
                    <LineChart data={attendanceTrend} margin={{ top: 10, right: 10, left: 0, bottom: 5 }}>
                      <CartesianGrid strokeDasharray="3 3" stroke="rgba(148,163,184,0.2)" />
                      <XAxis dataKey="date" tick={{ fill: 'currentColor', fontSize: 10 }} />
                      <YAxis domain={[0, 100]} tick={{ fill: 'currentColor', fontSize: 10 }} unit="%" />
                      <Tooltip
                        contentStyle={{ backgroundColor: 'var(--card)', border: '1px solid var(--border)', borderRadius: 12, color: 'var(--text)' }}
                        labelStyle={{ color: 'var(--text-light)', fontWeight: 700 }}
                        formatter={(v: number) => [`${v}%`, 'Present']}
                      />
                      <ReferenceLine y={75} stroke="#f59e0b" strokeDasharray="3 3" />
                      <Line type="monotone" dataKey="percent" stroke="#2563eb" strokeWidth={3} dot={{ r: 5, fill: '#2563eb' }} />
                    </LineChart>
                  </ResponsiveContainer>
                </div>
                <table className="sr-only">
                  <caption>Attendance percent over the last 5 school days.</caption>
                  <thead>
                    <tr><th scope="col">Date</th><th scope="col">Present</th></tr>
                  </thead>
                  <tbody>
                    {attendanceTrend.map((a) => (
                      <tr key={a.date}>
                        <th scope="row">{a.date}</th>
                        <td>{a.percent}%{a.percent < 75 ? ' (below 75% target)' : ''}</td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </>
            )}
          </div>
        </figure>
      </div>

      {/* Upcoming deadlines + Recent marks */}
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
        <section aria-labelledby="upcoming-deadlines-heading" className="lg:col-span-2 bg-card rounded-2xl border border-border overflow-hidden shadow-sm">
          <div className="px-6 py-4 border-b border-border bg-muted/50 flex items-center gap-2">
            <CalendarClock size={14} className="text-primary" aria-hidden="true" />
            <h3 id="upcoming-deadlines-heading" className="text-[0.65rem] font-black uppercase tracking-[2px] text-primary">Upcoming Deadlines (14d)</h3>
            <span className="ml-auto text-[0.7rem] font-bold text-text-muted">
              {studentUpcomingDeadlines.length} pending
            </span>
          </div>
          <div className="p-4 space-y-2 max-h-[420px] overflow-y-auto">
            {studentUpcomingDeadlines.length === 0 ? (
              <div className="text-center py-10 text-text-muted text-sm">
                <CheckCircle2 size={28} className="mx-auto mb-2 text-emerald-500 opacity-50" aria-hidden="true" />
                <p>No upcoming deadlines — you&apos;re all caught up!</p>
              </div>
            ) : (
              <>
                {urgentDeadlines.length > 0 && (
                  <h4 className="text-[0.6rem] uppercase font-black tracking-widest text-red-600 px-2 pt-2">
                    <AlertTriangle size={10} className="inline mr-1" aria-hidden="true" />Urgent
                  </h4>
                )}
                <ul className="space-y-2" aria-label="Urgent assignments">
                  {urgentDeadlines.map((d) => (
                    <li key={'u'+d.id}>
                      <DeadlineRow d={d} />
                    </li>
                  ))}
                </ul>
                {soonDeadlines.length > 0 && (
                  <h4 className="text-[0.6rem] uppercase font-black tracking-widest text-orange-600 px-2 pt-2">This week</h4>
                )}
                <ul className="space-y-2" aria-label="Assignments due this week">
                  {soonDeadlines.map((d) => (
                    <li key={'s'+d.id}>
                      <DeadlineRow d={d} />
                    </li>
                  ))}
                </ul>
                {studentUpcomingDeadlines
                  .filter((d) => d.urgency === 'normal')
                  .map((d) => (
                    <DeadlineRow key={'n'+d.id} d={d} />
                  ))}
              </>
            )}
          </div>
        </section>

        <section aria-labelledby="recent-marks-heading" className="bg-card border border-border rounded-2xl overflow-hidden shadow-sm">
          <div className="px-6 py-4 border-b border-border bg-muted/50 flex items-center gap-2">
            <Trophy size={14} className="text-primary" aria-hidden="true" />
            <h3 id="recent-marks-heading" className="text-[0.65rem] font-black uppercase tracking-[2px] text-primary">Recent Marks</h3>
          </div>
          <div className="p-4 space-y-3 max-h-[420px] overflow-y-auto">
            {(student.recent_marks?.length ?? 0) === 0 ? (
              <p className="text-center py-10 text-text-muted text-sm">No marks recorded yet.</p>
            ) : (
              <ul className="space-y-3" aria-label="Recent marks">
                {student.recent_marks!.map((m) => {
                  const scoreLabel = m.percent >= 70 ? 'on track' : m.percent >= 50 ? 'needs attention' : 'urgent';
                  return (
                    <li key={m.id} className="p-3 bg-muted/40 rounded-xl border border-border">
                      <div className="flex justify-between items-start gap-2">
                        <div className="min-w-0">
                          <p className="text-sm font-bold text-text truncate">{m.subject}</p>
                          <p className="text-[0.6rem] uppercase tracking-wider text-text-muted font-bold">{m.exam_type || 'Mark'}</p>
                        </div>
                        <div className="text-right shrink-0">
                          <p className="text-base font-black text-text">{m.marks}/{m.total_marks}</p>
                          <p className={`text-[0.65rem] font-black ${scoreLabel === 'on track' ? 'text-emerald-600 dark:text-emerald-400' : scoreLabel === 'needs attention' ? 'text-orange-600 dark:text-orange-400' : 'text-red-600 dark:text-red-400'}`}>
                            <span className="sr-only">{scoreLabel}: </span>
                            {m.percent}%
                          </p>
                        </div>
                      </div>
                    </li>
                  );
                })}
              </ul>
            )}
          </div>
        </section>
      </div>

      {student.feesSummary && student.feesSummary.pending > 0 && (
        <section
          aria-label={`Fees due: $${student.feesSummary.pending.toLocaleString()}`}
          className="bg-orange-50 dark:bg-orange-950/20 border border-orange-200 dark:border-orange-900/30 rounded-2xl p-6 flex items-center justify-between"
        >
          <div className="flex items-center gap-4">
            <div className="w-12 h-12 rounded-2xl bg-orange-500/10 flex items-center justify-center text-orange-600 border border-orange-200 dark:border-orange-900/40" aria-hidden="true">
              <DollarSign size={22} />
            </div>
            <div>
              <p className="text-[0.6rem] font-black uppercase tracking-widest text-orange-600">Fees Due</p>
              <p className="text-2xl font-black text-orange-700 dark:text-orange-300">${student.feesSummary.pending.toLocaleString()}</p>
            </div>
          </div>
          <Link
            to="/fees"
            className="px-4 py-2 bg-orange-600 hover:bg-orange-700 text-white rounded-xl font-bold text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-orange-500 focus-visible:ring-offset-2"
          >
            Pay now
          </Link>
        </section>
      )}
    </div>
  );
}

function DeadlineRow({ d }: { d: { id: number; title: string; due_date: string; days_until_due: number; urgency: string; subject_name: string | null; max_score: number | null } }) {
  const urgencyLabel = d.urgency === 'urgent' ? 'Urgent' : d.urgency === 'soon' ? 'Due this week' : 'Normal';
  const ariaLabel = `${d.title}, due in ${d.days_until_due} day${d.days_until_due === 1 ? '' : 's'} on ${d.due_date}, ${urgencyLabel.toLowerCase()}`;
  const urgencyColor = d.urgency === 'urgent' ? 'border-red-300 dark:border-red-900/40 bg-red-50/40 dark:bg-red-950/20'
    : d.urgency === 'soon' ? 'border-orange-200 dark:border-orange-900/30 bg-orange-50/30'
    : 'border-border bg-muted/30';
  const badge = d.urgency === 'urgent' ? 'bg-red-500/20 text-red-700 dark:text-red-300 border-red-300/40'
    : d.urgency === 'soon' ? 'bg-orange-500/20 text-orange-700 dark:text-orange-300 border-orange-300/40'
    : 'bg-blue-500/20 text-blue-700 dark:text-blue-300 border-blue-300/40';
  return (
    <Link
      to="/assignments"
      aria-label={ariaLabel}
      className={`flex items-center gap-3 p-3 rounded-xl border hover:border-primary transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ${urgencyColor}`}
    >
      <div className="w-10 h-10 rounded-xl bg-card flex flex-col items-center justify-center border border-border" aria-hidden="true">
        <span className="text-[0.55rem] uppercase font-black text-text-muted">in</span>
        <span className="text-sm font-black text-text leading-none">{d.days_until_due}d</span>
      </div>
      <div className="min-w-0 flex-1">
        <p className="text-sm font-bold text-text truncate">{d.title}</p>
        <p className="text-[0.65rem] text-text-muted">
          {d.subject_name && `${d.subject_name} • `}{d.due_date}{d.max_score && ` • ${d.max_score} pts`}
        </p>
      </div>
      <span
        className={`px-2.5 py-1 rounded-full text-[0.55rem] font-black uppercase tracking-wider border ${badge}`}
        aria-label={`Urgency: ${urgencyLabel}`}
      >
        <span aria-hidden="true">{d.urgency}</span>
      </span>
    </Link>
  );
}
