import { useEffect, useMemo, useState, type FormEvent, type ReactNode } from 'react'
import { Link, useNavigate, useParams, useSearchParams } from 'react-router-dom'
import './AdminDailyAttendance.css'
import { ApiHttpError } from '../api/http'
import { CiAcademicFilter } from '../components/CiPartials'
import { useSchoolYearOptions } from '../hooks/useSchoolYearOptions'
import {
  assignTeacherClass,
  assignStudentClass,
  autoDistributeStudents,
  banIp,
  createSubjectCurriculum,
  createAdministratorCalendarEvent,
  createClassSection,
  deleteSubjectCurriculum,
  deleteAdministratorCalendarEvent,
  deleteClassSection,
  deleteLateSlipLog,
  deleteTeacherClassAssignment,
  deleteUser,
  fetchAdministratorCalendarEvent,
  fetchAdministratorCalendarEvents,
  fetchAdministratorDailyAttendance,
  fetchBroadcastEmailOptions,
  fetchClassAssignmentOverview,
  fetchClassSections,
  fetchExamDraftAdminData,
  fetchFamilyAdminIndex,
  fetchGradingOverview,
  fetchIpBans,
  fetchLateSlipLogs,
  fetchNotificationAlerts,
  fetchPaypalTransactions,
  fetchPaypalTransactionsCsv,
  fetchPrintNotificationRecipients,
  fetchSchoolCalendarOptions,
  fetchRemovedStudents,
  fetchStudentDirectory,
  fetchStudentEmergencyContacts,
  fetchStudentParent,
  fetchStudentPromotionTotals,
  fetchSubjectCurriculum,
  fetchStudentAssignments,
  fetchTeacherClassAssignments,
  fetchTeacherSubmissions,
  fetchUsers,
  notifyTeacherSubmissions,
  openProtectedApiFile,
  removeStudentClass,
  reviewExamDraft,
  saveNotificationAlerts,
  savePrintNotificationRecipients,
  searchAdministratorDashboard,
  sendBroadcastEmail,
  setStudentActive,
  unbanIp,
  uploadLegacyExamDraft,
  updateAdministratorAttendance,
  updateAdministratorCalendarEvent,
  updateClassSection,
  updateStudentProfile,
  updateSubjectCurriculum,
} from '../api/session'
import type {
  AdministratorDailyAttendanceEntry,
  AdministratorDailyAttendanceSection,
  AdministratorDailyAttendanceStudent,
  AdministratorDailyAttendanceSummary,
  AdministratorDashboardSearchResponse,
  BroadcastEmailParentOption,
  ClassSectionRow,
  ExamDraftRow,
  GradingOverviewStudentRow,
  NotificationAdminRow,
  RemovedStudentRow,
  SchoolCalendarDetailRow,
  SchoolCalendarEventRow,
  StudentDirectoryRow,
  StudentAssignmentOption,
  StudentAssignmentRow,
  StudentPromotionTotalsRow,
  SubjectCurriculumEntryRow,
  TeacherClassAssignmentRow,
  TeacherClassOption,
  TeacherSubmissionReportRow,
  UserListRow,
} from '../api/types'
function AdminParityShell({
  title,
  children,
  showTitle = true,
}: {
  title: string
  children: ReactNode
  showTitle?: boolean
}) {
  return (
    <div className="container-fluid py-3">
      {showTitle ? (
        <div className="mb-4">
          <h2 className="h4 mb-1">{title}</h2>
        </div>
      ) : null}
      {children}
    </div>
  )
}

function formatDate(value?: string | null) {
  if (!value) return '—'
  const date = new Date(value)
  return Number.isNaN(date.getTime()) ? value : date.toLocaleDateString()
}

function formatDateInput(value?: string | null) {
  return value ? String(value).slice(0, 10) : ''
}

function SortTh({
  col, label, sortCol, sortDir, onSort, style,
}: {
  col: string; label: string; sortCol: string; sortDir: 'asc' | 'desc'
  onSort: (c: string) => void; style?: React.CSSProperties
}) {
  const active = sortCol === col
  return (
    <th style={{ cursor: 'pointer', userSelect: 'none', whiteSpace: 'nowrap', ...style }} onClick={() => onSort(col)}>
      {label}{' '}
      <span style={{ opacity: active ? 1 : 0.3 }}>{active && sortDir === 'desc' ? '▼' : '▲'}</span>
    </th>
  )
}

function normalizeAttendanceSearch(value: string) {
  return value.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()
}

function attendanceSearchMatchesPrefix(query: string, values: string[]) {
  if (query === '') return true
  return values.some((value) => {
    const normalized = normalizeAttendanceSearch(value)
    if (normalized.startsWith(query)) return true
    return normalized.split(' ').some((part) => part.startsWith(query))
  })
}

/** MM-DD-YYYY for table headers (matches legacy attendance grid). */
function formatAttendanceMdY(value?: string | null) {
  if (!value) return '—'
  const s = String(value).slice(0, 10)
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s)
  if (m) return `${m[2]}-${m[3]}-${m[1]}`
  return formatDate(value)
}

function nextSundayAfter(dateStr: string): string | null {
  if (!/^\d{4}-\d{2}-\d{2}$/.test(dateStr)) return null
  const d = new Date(dateStr + 'T00:00:00')
  if (isNaN(d.getTime())) return null
  const daysUntil = d.getDay() === 0 ? 7 : 7 - d.getDay()
  d.setDate(d.getDate() + daysUntil)
  return d.toISOString().slice(0, 10)
}

function attendanceEntryIsReported(isReported: string | null | undefined) {
  const v = String(isReported ?? '')
    .trim()
    .toLowerCase()
  return v === 'yes' || v === '1' || v === 'true'
}

function entryToAttendanceSelectValue(entry?: { status: string; isReported?: boolean }) {
  if (!entry) return ''
  const s = String(entry.status ?? '').toLowerCase()
  if (s === 'present') return 'present'
  if (s === 'absent') return entry.isReported ? 'absent_reported' : 'absent'
  if (s === 'late') return entry.isReported ? 'late_reported' : 'late'
  return ''
}

function attendanceCellSelectClass(val: string) {
  const base = 'form-select form-select-sm att-cell-select'
  if (val === 'present') return `${base} att-sel-present`
  if (val === 'absent') return `${base} att-sel-absent`
  if (val === 'absent_reported') return `${base} att-sel-absent-reported`
  if (val === 'late_reported') return `${base} att-sel-late-reported`
  if (val === 'late') return `${base} att-sel-late`
  return `${base} att-sel-empty`
}

function monthLabel(value: string) {
  const date = new Date(`${value}T00:00:00`)
  if (Number.isNaN(date.getTime())) return value
  return date.toLocaleString(undefined, { month: 'long', year: 'numeric' })
}

function eventAudienceBadges(row: SchoolCalendarDetailRow | SchoolCalendarEventRow) {
  const props: Record<string, unknown> =
    'extendedProps' in row
      ? { ...(row.extendedProps ?? {}) }
      : {
          notify_parent: (row as SchoolCalendarDetailRow).notify_parent,
          notify_teacher: (row as SchoolCalendarDetailRow).notify_teacher,
          notify_admin: (row as SchoolCalendarDetailRow).notify_admin,
        }
  return [
    props.notify_parent ? 'Parents' : null,
    props.notify_teacher ? 'Teachers' : null,
    props.notify_admin ? 'Admins' : null,
  ].filter(Boolean) as string[]
}

type AttendanceSectionSnapshot = {
  sectionId: string
  classId: number
  className: string
  students: Array<{
    id: number
    schoolId: string
    name: string
    summary: { present: number; late: number; absent: number; total: number }
    entriesByDate: Record<string, { status: string; reason?: string | null; isReported?: boolean }>
  }>
  dates: string[]
}

type AttendanceRenderedStudentRow = {
  sectionId: string
  sectionName: string
  student: AttendanceSectionSnapshot['students'][number]
}

type AttendanceGradeGroup = {
  key: string
  label: string
  order: number
  sections: AttendanceSectionSnapshot[]
}

function recordPick<T>(map: Record<string, T> | undefined, id: string): T | undefined {
  if (!map) return undefined
  if (map[id] !== undefined) return map[id]
  const n = Number(id)
  if (!Number.isNaN(n) && map[String(n)] !== undefined) return map[String(n)]
  return undefined
}

function buildAttendanceSections(data: Awaited<ReturnType<typeof fetchAdministratorDailyAttendance>>): AttendanceSectionSnapshot[] {
  const raw = data as unknown as Record<string, unknown>
  const grades = (data.grades ?? raw.Grades ?? raw.grade_sections ?? raw.sections) as
    | Record<string, AdministratorDailyAttendanceSection[]>
    | AdministratorDailyAttendanceSection[]
    | undefined
  const gradesEntries = Array.isArray(grades)
    ? grades.map((row, idx) => [String(idx), [row]] as const)
    : Object.entries(grades ?? {})
  const studentsBySection = (data.students_by_section ?? raw.studentsBySection ?? {}) as Record<
    string,
    AdministratorDailyAttendanceStudent[]
  >
  const attendanceData = (data.attendance_data ?? raw.attendanceData ?? {}) as Record<
    string,
    Record<string, AdministratorDailyAttendanceEntry[]>
  >
  const attendanceRecord = (data.attendance_record ?? raw.attendanceRecord ?? {}) as Record<
    string,
    Record<string, AdministratorDailyAttendanceSummary>
  >
  const datesBySection = (data.dates_by_section ?? raw.datesBySection ?? {}) as Record<string, string[]>
  const globalDateList = Array.isArray(data.date_list)
    ? data.date_list.filter((x): x is string => typeof x === 'string' && x.length > 0)
    : Array.isArray(raw.dateList)
      ? (raw.dateList as unknown[]).filter((x): x is string => typeof x === 'string' && x.length > 0)
      : []
  const sections: AttendanceSectionSnapshot[] = []

  for (const [classIdKey, sectionRows] of gradesEntries) {
    for (const row of sectionRows ?? []) {
      const rowIds = row as AdministratorDailyAttendanceSection & { section_id?: number | string }
      const sectionId = String(row.class_section_id ?? rowIds.section_id ?? row.id ?? '')
      if (!sectionId) continue

      const rowExtra = row as AdministratorDailyAttendanceSection & {
        students?: AdministratorDailyAttendanceStudent[]
      }
      let studentSource = recordPick(studentsBySection, sectionId)
      if (!studentSource?.length && Array.isArray(rowExtra.students)) {
        studentSource = rowExtra.students
      }

      const sectionAttendance = recordPick(attendanceData, sectionId)
      const sectionSummaryMap = recordPick(attendanceRecord, sectionId)

      const students = (studentSource ?? []).map((student) => {
        const studentId = Number(student.id)
        const entries = sectionAttendance?.[String(studentId)] ?? []
        const summary = sectionSummaryMap?.[String(studentId)] ?? {}
        return {
          id: studentId,
          schoolId: student.school_id ?? '—',
          name: `${student.firstname ?? ''} ${student.lastname ?? ''}`.trim() || `Student ${studentId}`,
          summary: {
            present: Number(summary.total_presence ?? 0),
            late: Number(summary.total_late ?? 0),
            absent: Number(summary.total_absence ?? 0),
            total: Number(summary.total_attendance ?? 0),
          },
          entriesByDate: Object.fromEntries(
            entries.map((entry) => [
              String(entry.date ?? ''),
              {
                status: String(entry.status ?? ''),
                reason: entry.reason ?? null,
                isReported: attendanceEntryIsReported(entry.is_reported ?? null),
              },
            ]),
          ),
        }
      })

      if (students.length === 0) continue

      const perSectionDates = recordPick(datesBySection, sectionId) ?? []
      const dates = perSectionDates.length > 0 ? perSectionDates : globalDateList

      sections.push({
        sectionId,
        classId: Number(classIdKey),
        className: row.class_section_name ?? `Section ${sectionId}`,
        students,
        dates,
      })
    }
  }

  return sections.sort((a, b) => {
    if (a.classId !== b.classId) return a.classId - b.classId
    return a.className.localeCompare(b.className)
  })
}

function buildAttendanceGradeGroups(sections: AttendanceSectionSnapshot[]): AttendanceGradeGroup[] {
  const groups = new Map<string, AttendanceGradeGroup>()

  function bucketFor(section: AttendanceSectionSnapshot): { key: string; label: string; order: number } {
    const name = section.className
    if (/\bkg\b/i.test(name)) return { key: 'kg', label: 'KG', order: 0 }
    if (/\byouth\b/i.test(name)) return { key: 'youth', label: 'Youth', order: 99 }
    if (/\barabic\b/i.test(name)) return { key: 'arabic', label: 'Arabic', order: 100 }
    const gradeMatch = /\bgrade\s*(\d+)\b/i.exec(name)
    if (gradeMatch) {
      const n = Number(gradeMatch[1])
      return { key: `g${n}`, label: `Grade ${n}`, order: n }
    }
    if (section.classId === 0) return { key: 'kg', label: 'KG', order: 0 }
    if (section.classId === 13) return { key: 'youth', label: 'Youth', order: 99 }
    return { key: `g${section.classId}`, label: `Grade ${section.classId}`, order: section.classId }
  }

  for (const section of sections) {
    const bucket = bucketFor(section)
    const existing = groups.get(bucket.key) ?? { ...bucket, sections: [] }
    existing.sections.push(section)
    groups.set(bucket.key, existing)
  }

  return Array.from(groups.values())
    .map((group) => ({
      ...group,
      sections: group.sections.sort((a, b) => a.className.localeCompare(b.className)),
    }))
    .sort((a, b) => a.order - b.order || a.label.localeCompare(b.label))
}

function buildAttendanceAnalysis(sections: AttendanceSectionSnapshot[]) {
  const overall = { present: 0, late: 0, absent: 0 }
  const byClass = new Map<string, { present: number; late: number; absent: number; totalStudents: number }>()
  const studentsNeedingAttention: Array<{
    name: string
    schoolId: string
    className: string
    absent: number
    late: number
  }> = []

  for (const section of sections) {
    if (!byClass.has(section.className)) {
      byClass.set(section.className, { present: 0, late: 0, absent: 0, totalStudents: section.students.length })
    }
    const bucket = byClass.get(section.className)!

    for (const student of section.students) {
      overall.present += student.summary.present
      overall.late += student.summary.late
      overall.absent += student.summary.absent
      bucket.present += student.summary.present
      bucket.late += student.summary.late
      bucket.absent += student.summary.absent

      if (student.summary.absent > 0 || student.summary.late > 0) {
        studentsNeedingAttention.push({
          name: student.name,
          schoolId: student.schoolId,
          className: section.className,
          absent: student.summary.absent,
          late: student.summary.late,
        })
      }
    }
  }

  studentsNeedingAttention.sort((a, b) => {
    if (b.absent !== a.absent) return b.absent - a.absent
    if (b.late !== a.late) return b.late - a.late
    return a.name.localeCompare(b.name)
  })

  return { overall, byClass: Array.from(byClass.entries()), studentsNeedingAttention }
}

export function AdminBroadcastEmailPage() {
  const [parents, setParents] = useState<BroadcastEmailParentOption[]>([])
  const [fromOptions, setFromOptions] = useState<{ key: string; label: string }[]>([])
  const [selectedIds, setSelectedIds] = useState<number[]>([])
  const [filter, setFilter] = useState('')
  const [loading, setLoading] = useState(true)
  const [submitting, setSubmitting] = useState(false)
  const [message, setMessage] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [form, setForm] = useState({
    from_key: '',
    mode: 'personalized' as 'personalized' | 'standard',
    subject: '',
    body_html: '',
    wrap_layout: true,
    preheader: '',
    cta_text: '',
    cta_url: '',
    test_email: '',
  })

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const data = await fetchBroadcastEmailOptions()
        if (cancelled) return
        setParents(data.parents ?? [])
        setFromOptions(data.fromOptions ?? [])
        setForm((current) => ({
          ...current,
          from_key: current.from_key || data.fromOptions?.[0]?.key || '',
        }))
        setError(null)
      } catch (e) {
        if (!cancelled) {
          setError(e instanceof Error ? e.message : 'Unable to load broadcast email options.')
        }
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [])

  const filteredParents = useMemo(() => {
    const q = filter.trim().toLowerCase()
    if (!q) return parents
    return parents.filter((row) => {
      const haystack = `${row.firstname ?? ''} ${row.lastname ?? ''} ${row.email ?? ''} ${row.school_id ?? ''}`.toLowerCase()
      return haystack.includes(q)
    })
  }, [filter, parents])

  function toggleSelected(id: number) {
    setSelectedIds((current) =>
      current.includes(id) ? current.filter((item) => item !== id) : [...current, id],
    )
  }

  function selectAllFiltered() {
    setSelectedIds(Array.from(new Set([...selectedIds, ...filteredParents.map((row) => row.id)])))
  }

  async function submit(sendTestOnly: boolean) {
    setSubmitting(true)
    setMessage(null)
    setError(null)
    try {
      const result = await sendBroadcastEmail({
        ...form,
        send_test_only: sendTestOnly,
        parent_ids: sendTestOnly ? [] : selectedIds,
      })
      if (!result.ok) {
        setError(result.message ?? 'Broadcast failed.')
      } else {
        setMessage(result.message ?? 'Broadcast sent.')
      }
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Broadcast failed.')
    } finally {
      setSubmitting(false)
    }
  }

  return (
    <AdminParityShell title="Broadcast Email to Parents">
      {message ? <div className="alert alert-success">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="card mb-3">
        <div className="card-header">Email Details</div>
        <div className="card-body row g-3">
          <div className="col-md-6">
            <label className="form-label">From</label>
            <select
              className="form-select"
              value={form.from_key}
              onChange={(event) => setForm((current) => ({ ...current, from_key: event.target.value }))}
              disabled={loading || submitting}
            >
              {fromOptions.map((option) => (
                <option key={option.key} value={option.key}>
                  {option.label}
                </option>
              ))}
            </select>
          </div>

          <div className="col-md-6">
            <label className="form-label">Send Mode</label>
            <select
              className="form-select"
              value={form.mode}
              onChange={(event) =>
                setForm((current) => ({
                  ...current,
                  mode: event.target.value as 'personalized' | 'standard',
                }))
              }
              disabled={submitting}
            >
              <option value="personalized">Personalized</option>
              <option value="standard">Standard</option>
            </select>
          </div>

          <div className="col-md-8">
            <label className="form-label">Subject</label>
            <input
              className="form-control"
              value={form.subject}
              onChange={(event) => setForm((current) => ({ ...current, subject: event.target.value }))}
              disabled={submitting}
            />
          </div>

          <div className="col-md-4 d-flex align-items-end">
            <div className="form-check">
              <input
                id="wrap_layout"
                className="form-check-input"
                type="checkbox"
                checked={form.wrap_layout}
                onChange={(event) =>
                  setForm((current) => ({ ...current, wrap_layout: event.target.checked }))
                }
                disabled={submitting}
              />
              <label className="form-check-label" htmlFor="wrap_layout">
                Wrap with email layout
              </label>
            </div>
          </div>

          <div className="col-12">
            <label className="form-label">Message (HTML)</label>
            <textarea
              className="form-control"
              rows={10}
              value={form.body_html}
              onChange={(event) => setForm((current) => ({ ...current, body_html: event.target.value }))}
              placeholder="Dear {{name}}, ..."
              disabled={submitting}
            />
          </div>

          <div className="col-md-6">
            <label className="form-label">Preheader</label>
            <input
              className="form-control"
              value={form.preheader}
              onChange={(event) => setForm((current) => ({ ...current, preheader: event.target.value }))}
              disabled={submitting}
            />
          </div>

          <div className="col-md-3">
            <label className="form-label">CTA Text</label>
            <input
              className="form-control"
              value={form.cta_text}
              onChange={(event) => setForm((current) => ({ ...current, cta_text: event.target.value }))}
              disabled={submitting}
            />
          </div>

          <div className="col-md-3">
            <label className="form-label">CTA URL</label>
            <input
              className="form-control"
              value={form.cta_url}
              onChange={(event) => setForm((current) => ({ ...current, cta_url: event.target.value }))}
              disabled={submitting}
            />
          </div>
        </div>
        <div className="card-footer d-flex flex-wrap gap-2 align-items-center">
          <div className="input-group" style={{ maxWidth: 420 }}>
            <span className="input-group-text">Test email</span>
            <input
              className="form-control"
              type="email"
              value={form.test_email}
              onChange={(event) => setForm((current) => ({ ...current, test_email: event.target.value }))}
              disabled={submitting}
            />
            <button
              className="btn btn-outline-primary"
              type="button"
              onClick={() => submit(true)}
              disabled={submitting}
            >
              Send Test Only
            </button>
          </div>
          <span className="ms-auto fw-semibold">Selected: {selectedIds.length}</span>
          <button
            className="btn btn-primary"
            type="button"
            onClick={() => submit(false)}
            disabled={submitting || selectedIds.length === 0}
          >
            Send Broadcast
          </button>
        </div>
      </div>

      <div className="card">
        <div className="card-header d-flex justify-content-between align-items-center gap-2 flex-wrap">
          <span>Parents</span>
          <div className="d-flex gap-2">
            <input
              className="form-control form-control-sm"
              style={{ minWidth: 260 }}
              placeholder="Filter by name, email, school ID"
              value={filter}
              onChange={(event) => setFilter(event.target.value)}
            />
            <button className="btn btn-sm btn-outline-secondary" type="button" onClick={selectAllFiltered}>
              Select Filtered
            </button>
            <button
              className="btn btn-sm btn-outline-secondary"
              type="button"
              onClick={() => setSelectedIds([])}
            >
              Clear
            </button>
          </div>
        </div>
        <div className="card-body p-0">
          <div className="table-responsive">
            <table className="table table-striped table-hover align-middle mb-0">
              <thead className="table-dark">
                <tr>
                  <th style={{ width: 48 }}>#</th>
                  <th>Name</th>
                  <th>Email</th>
                  <th>School ID</th>
                </tr>
              </thead>
              <tbody>
                {loading ? (
                  <tr>
                    <td colSpan={4} className="text-muted">Loading parents…</td>
                  </tr>
                ) : filteredParents.length === 0 ? (
                  <tr>
                    <td colSpan={4} className="text-muted">No parents found.</td>
                  </tr>
                ) : (
                  filteredParents.map((row) => (
                    <tr key={row.id}>
                      <td>
                        <input
                          type="checkbox"
                          className="form-check-input"
                          checked={selectedIds.includes(row.id)}
                          onChange={() => toggleSelected(row.id)}
                        />
                      </td>
                      <td>{`${row.firstname ?? ''} ${row.lastname ?? ''}`.trim() || '—'}</td>
                      <td>{row.email ?? '—'}</td>
                      <td>{row.school_id ?? '—'}</td>
                    </tr>
                  ))
                )}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

function CalendarEventForm({
  title,
  initial,
  submitLabel,
  onSubmit,
  submitting,
}: {
  title: string
  initial: Partial<SchoolCalendarDetailRow> & {
    event_types?: string[]
    defaults?: { school_year?: string | null; semester?: string | null }
  }
  submitLabel: string
  onSubmit: (payload: Record<string, unknown>) => Promise<void>
  submitting: boolean
}) {
  const navigate = useNavigate()
  const [form, setForm] = useState({
    title: initial.title ?? '',
    description: initial.description ?? '',
    event_type: initial.event_type ?? '',
    date: formatDateInput(initial.date),
    notify_parent: Boolean(initial.notify_parent),
    notify_teacher: Boolean(initial.notify_teacher),
    notify_admin: Boolean(initial.notify_admin),
    no_school: Boolean(initial.no_school),
    send_email_parent: false,
    send_email_teacher: false,
    send_email_admin: false,
    school_year: initial.school_year ?? initial.defaults?.school_year ?? '',
    semester: initial.semester ?? initial.defaults?.semester ?? '',
  })
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setForm({
      title: initial.title ?? '',
      description: initial.description ?? '',
      event_type: initial.event_type ?? '',
      date: formatDateInput(initial.date),
      notify_parent: Boolean(initial.notify_parent),
      notify_teacher: Boolean(initial.notify_teacher),
      notify_admin: Boolean(initial.notify_admin),
      no_school: Boolean(initial.no_school),
      send_email_parent: false,
      send_email_teacher: false,
      send_email_admin: false,
      school_year: initial.school_year ?? initial.defaults?.school_year ?? '',
      semester: initial.semester ?? initial.defaults?.semester ?? '',
    })
  }, [initial])

  async function handleSubmit(event: FormEvent) {
    event.preventDefault()
    setError(null)
    try {
      await onSubmit(form)
    } catch (e) {
      setError(e instanceof Error ? e.message : `Unable to ${submitLabel.toLowerCase()}.`)
    }
  }

  return (
    <AdminParityShell title={title}>
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <form className="card" onSubmit={handleSubmit}>
        <div className="card-body row g-3">
          <div className="col-12">
            <div className="form-check form-switch mb-2">
              <input
                id="no_school"
                className="form-check-input"
                type="checkbox"
                checked={form.no_school}
                onChange={(event) => setForm((current) => ({ ...current, no_school: event.target.checked }))}
              />
              <label className="form-check-label" htmlFor="no_school">
                No School Day
              </label>
            </div>
            <label className="form-label">Title</label>
            <input
              className="form-control"
              value={form.title}
              onChange={(event) => setForm((current) => ({ ...current, title: event.target.value }))}
              required
            />
          </div>

          <div className="col-12">
            <label className="form-label">Description</label>
            <textarea
              className="form-control"
              rows={4}
              value={form.description}
              onChange={(event) => setForm((current) => ({ ...current, description: event.target.value }))}
            />
          </div>

          <div className="col-md-4">
            <label className="form-label">Event Type</label>
            <select
              className="form-select"
              value={form.event_type}
              onChange={(event) => setForm((current) => ({ ...current, event_type: event.target.value }))}
            >
              <option value="">— Select event type —</option>
              {(initial.event_types ?? []).map((type) => (
                <option key={type} value={type}>
                  {type}
                </option>
              ))}
            </select>
          </div>

          <div className="col-md-4">
            <label className="form-label">Event Date</label>
            <input
              className="form-control"
              type="date"
              value={form.date}
              onChange={(event) => setForm((current) => ({ ...current, date: event.target.value }))}
              required
            />
          </div>

          <div className="col-md-4">
            <label className="form-label">School Year</label>
            <input
              className="form-control"
              value={form.school_year}
              onChange={(event) => setForm((current) => ({ ...current, school_year: event.target.value }))}
            />
          </div>

          <div className="col-md-4">
            <label className="form-label">Semester</label>
            <select
              className="form-select"
              value={form.semester}
              onChange={(event) => setForm((current) => ({ ...current, semester: event.target.value }))}
            >
              <option value="">—</option>
              <option value="Fall">Fall</option>
              <option value="Spring">Spring</option>
            </select>
          </div>

          <div className="col-md-8">
            <label className="form-label d-block">Calendar Display</label>
            <div className="d-flex gap-3 flex-wrap">
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.notify_parent}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, notify_parent: event.target.checked }))
                  }
                />
                Parents
              </label>
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.notify_teacher}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, notify_teacher: event.target.checked }))
                  }
                />
                Teachers
              </label>
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.notify_admin}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, notify_admin: event.target.checked }))
                  }
                />
                Admins
              </label>
            </div>
          </div>

          <div className="col-12">
            <label className="form-label d-block">Email Notifications</label>
            <div className="d-flex gap-3 flex-wrap">
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.send_email_parent}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, send_email_parent: event.target.checked }))
                  }
                />
                Send to Parents
              </label>
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.send_email_teacher}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, send_email_teacher: event.target.checked }))
                  }
                />
                Send to Teachers
              </label>
              <label className="form-check-label">
                <input
                  className="form-check-input me-1"
                  type="checkbox"
                  checked={form.send_email_admin}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, send_email_admin: event.target.checked }))
                  }
                />
                Send to Admins
              </label>
            </div>
          </div>
        </div>
        <div className="card-footer d-flex gap-2 justify-content-end">
          <button type="button" className="btn btn-secondary" onClick={() => navigate('/app/administrator/events')}>
            Cancel
          </button>
          <button className="btn btn-primary" type="submit" disabled={submitting}>
            {submitLabel}
          </button>
        </div>
      </form>
    </AdminParityShell>
  )
}

export function AdminCalendarAddEventPage() {
  const navigate = useNavigate()
  const [options, setOptions] = useState<{ event_types: string[]; defaults: { school_year?: string | null; semester?: string | null } } | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const data = await fetchSchoolCalendarOptions()
        if (!cancelled) setOptions(data.data ?? null)
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [])

  if (loading && !options) {
    return <AdminParityShell title="Add Event"><p className="text-muted">Loading…</p></AdminParityShell>
  }

  return (
    <CalendarEventForm
      title="Add Event"
      initial={{
        event_types: options?.event_types ?? [],
        defaults: options?.defaults,
      }}
      submitLabel="Add Event"
      submitting={false}
      onSubmit={async (payload) => {
        await createAdministratorCalendarEvent(payload as never)
        navigate('/app/administrator/events')
      }}
    />
  )
}

export function AdminCalendarEditPage() {
  const navigate = useNavigate()
  const { eventId } = useParams()
  const [options, setOptions] = useState<{ event_types: string[]; defaults: { school_year?: string | null; semester?: string | null } } | null>(null)
  const [event, setEvent] = useState<SchoolCalendarDetailRow | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const [optionsRes, eventRes] = await Promise.all([
          fetchSchoolCalendarOptions(),
          fetchAdministratorCalendarEvent(Number(eventId)),
        ])
        if (cancelled) return
        setOptions(optionsRes.data ?? null)
        setEvent(eventRes.data?.event ?? null)
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [eventId])

  if (loading || !event) {
    return <AdminParityShell title="Edit Event"><p className="text-muted">Loading…</p></AdminParityShell>
  }

  return (
    <CalendarEventForm
      title="Edit Event"
      initial={{
        ...event,
        event_types: options?.event_types ?? [],
        defaults: options?.defaults,
      }}
      submitLabel="Update Event"
      submitting={false}
      onSubmit={async (payload) => {
        await updateAdministratorCalendarEvent(Number(eventId), payload)
        navigate('/app/administrator/events')
      }}
    />
  )
}

/** School calendar admin — `GET /api/v1/settings/school-calendar/events` (JWT). SPA: `/app/administrator/events` or `calendar_view`. */

export function AdminCalendarViewPage() {
  const navigate = useNavigate()
  const [searchParams, setSearchParams] = useSearchParams()
  const [events, setEvents] = useState<SchoolCalendarEventRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const schoolYear = searchParams.get('school_year') ?? ''
  const { options, currentYear } = useSchoolYearOptions({
    preferredYear: schoolYear,
  })

  useEffect(() => {
    if (!schoolYear && currentYear) {
      setSearchParams(new URLSearchParams({ school_year: currentYear }), { replace: true })
    }
  }, [currentYear, schoolYear, setSearchParams])

  async function load() {
    setLoading(true)
    try {
      const data = await fetchAdministratorCalendarEvents({
        schoolYear: schoolYear || null,
        semester: null,
      })
      setEvents(data.data?.events ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load calendar events.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [schoolYear])

  async function onDelete(eventId: number) {
    if (!window.confirm('Delete this event?')) return
    await deleteAdministratorCalendarEvent(eventId)
    await load()
  }

  return (
    <AdminParityShell title="Event list">
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="d-flex gap-2 mb-3 flex-wrap justify-content-between align-items-center">
        <Link to="/app/administrator/calendar" className="btn btn-outline-secondary">
          Browse calendar
        </Link>
        <Link
          to={`/app/administrator/calendar_add_event${schoolYear ? `?school_year=${encodeURIComponent(schoolYear)}` : ''}`}
          className="btn btn-success"
        >
          Add New Event
        </Link>
      </div>

      <form
        className="mb-3 d-flex gap-2 justify-content-center align-items-end flex-wrap"
        onSubmit={(event) => {
          event.preventDefault()
          const year = String(new FormData(event.currentTarget).get('school_year') ?? '').trim()
          const next = new URLSearchParams()
          if (year) next.set('school_year', year)
          setSearchParams(next)
        }}
      >
        <div>
          <label htmlFor="cal-school-year" className="form-label">School Year</label>
          <select
            id="cal-school-year"
            name="school_year"
            className="form-select"
            defaultValue={schoolYear || currentYear}
          >
            {options.map((option) => (
              <option key={option.value} value={option.value}>
                {option.label}
              </option>
            ))}
          </select>
        </div>
        <div className="d-flex gap-2 align-self-end">
          <button className="btn btn-secondary" type="submit">Apply</button>
          <button
            className="btn btn-outline-secondary"
            type="button"
            onClick={() =>
              setSearchParams(new URLSearchParams(currentYear ? { school_year: currentYear } : {}))
            }
          >
            Reset
          </button>
        </div>
      </form>

      <div className="table-responsive">
        <table className="table table-striped align-middle">
          <thead>
            <tr>
              <th>ID</th>
              <th>Title</th>
              <th>Type</th>
              <th>Description</th>
              <th>Date</th>
              <th>Audience</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={7} className="text-muted">Loading events…</td></tr>
            ) : events.length === 0 ? (
              <tr><td colSpan={7} className="text-muted">No events found.</td></tr>
            ) : (
              events.map((row) => (
                <tr key={row.id ?? row.title + row.start}>
                  <td>{row.id ?? '—'}</td>
                  <td>{row.title}</td>
                  <td>{String(row.extendedProps?.event_type ?? '—')}</td>
                  <td>{row.description || '—'}</td>
                  <td>{formatDate(row.start)}</td>
                  <td>{eventAudienceBadges(row).join(', ') || '—'}</td>
                  <td className="d-flex gap-2 flex-wrap">
                    {row.id ? (
                      <>
                        <button className="btn btn-primary btn-sm" type="button" onClick={() => navigate(`/app/administrator/calendar_edit/${row.id}`)}>
                          Edit
                        </button>
                        <button className="btn btn-danger btn-sm" type="button" onClick={() => onDelete(row.id as number)}>
                          Delete
                        </button>
                      </>
                    ) : (
                      <span className="text-muted small">Meeting event</span>
                    )}
                  </td>
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminCalendarPage() {
  const [events, setEvents] = useState<SchoolCalendarEventRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const data = await fetchAdministratorCalendarEvents()
        if (cancelled) return
        setEvents(data.data?.events ?? [])
        setError(null)
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load calendar.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [])

  const grouped = useMemo(() => {
    const map = new Map<string, SchoolCalendarEventRow[]>()
    for (const row of events) {
      const key = formatDateInput(row.start).slice(0, 7)
      if (!map.has(key)) map.set(key, [])
      map.get(key)?.push(row)
    }
    return Array.from(map.entries())
      .sort(([a], [b]) => a.localeCompare(b))
      .map(([month, rows]) => ({ month, rows }))
  }, [events])

  return (
    <AdminParityShell title="School calendar">
      <div className="d-flex justify-content-end mb-3">
        <Link to="/app/administrator/events" className="btn btn-outline-secondary">
          Manage events (list)
        </Link>
      </div>
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted">Loading calendar…</p>
      ) : grouped.length === 0 ? (
        <p className="text-muted">No calendar events found.</p>
      ) : (
        <div className="row g-3">
          {grouped.map((group) => (
            <div key={group.month} className="col-12 col-xl-6">
              <div className="card h-100">
                <div className="card-header">{monthLabel(`${group.month}-01`)}</div>
                <div className="list-group list-group-flush">
                  {group.rows.map((row) => (
                    <div key={String(row.id ?? row.start + row.title)} className="list-group-item">
                      <div className="d-flex justify-content-between gap-3">
                        <div>
                          <div className="fw-semibold">{row.title}</div>
                          <div className="small text-muted">{formatDate(row.start)}</div>
                          {row.description ? <div className="small mt-1">{row.description}</div> : null}
                        </div>
                        <div className="text-end small text-muted">
                          <div>{String(row.extendedProps?.event_type ?? 'General')}</div>
                          <div>{eventAudienceBadges(row).join(', ') || '—'}</div>
                        </div>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </div>
          ))}
        </div>
      )}
    </AdminParityShell>
  )
}

export function AdminClassAssignmentPage() {
  type ClassAssignmentStudent = {
    id?: number
    firstname?: string | null
    lastname?: string | null
    age?: number | string | null
    gender?: string | null
    photo_consent?: boolean | number | null
    tuition_paid?: boolean | number | null
    school_id?: string | null
  }
  type ClassAssignmentSortKey = 'school_id' | 'firstname' | 'lastname' | 'age' | 'gender' | 'photo_consent'
  const [sections, setSections] = useState<
    Array<{
      class_section_id?: number | null
      class_section_name?: string | null
      main_teachers?: string[]
      mainTeachers?: string[]
      teacher_assistants?: string[]
      teacherAssistants?: string[]
      students?: ClassAssignmentStudent[]
      semester?: string | null
      school_year?: string | null
      description?: string | null
    }>
  >([])
  const [schoolYears, setSchoolYears] = useState<string[]>([])
  const [selectedYear, setSelectedYear] = useState('')
  const [loading, setLoading] = useState(true)
  const [message] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [selectedSemester, setSelectedSemester] = useState('')
  const [expandedSections, setExpandedSections] = useState<Set<string>>(new Set(['0']))
  const [sortConfig, setSortConfig] = useState<{ key: ClassAssignmentSortKey; direction: 'asc' | 'desc' }>({
    key: 'school_id',
    direction: 'asc',
  })
  const { options, selectedYear: defaultYear } = useSchoolYearOptions({
    legacyYears: schoolYears,
    preferredYear: selectedYear,
  })

  async function load(year?: string | null) {
    setLoading(true)
    try {
      const response = await fetchClassAssignmentOverview(year ?? null, null)
      const data = response.data ?? {}
      const classSections = data.classSections ?? []
      setSections(classSections)
      setSchoolYears(data.schoolYears ?? [])
      setSelectedYear(data.selectedYear ?? data.schoolYear ?? defaultYear)
      setSelectedSemester(data.selectedSemester ?? data.semester ?? '')
      setExpandedSections(new Set(classSections.length > 0 ? ['0'] : []))
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load class assignments.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load(null)
  }, [])

  function toggleSection(key: string) {
    setExpandedSections((prev) => {
      const next = new Set(prev)
      next.has(key) ? next.delete(key) : next.add(key)
      return next
    })
  }

  function requestSort(key: ClassAssignmentSortKey) {
    setSortConfig((prev) =>
      prev.key === key
        ? { key, direction: prev.direction === 'asc' ? 'desc' : 'asc' }
        : { key, direction: 'asc' },
    )
  }

  function sortIndicator(key: ClassAssignmentSortKey) {
    if (sortConfig.key !== key) return '↕'
    return sortConfig.direction === 'asc' ? '↑' : '↓'
  }

  function sortedStudents(students: ClassAssignmentStudent[]) {
    return [...students].sort((left, right) => {
      const dir = sortConfig.direction === 'asc' ? 1 : -1
      const leftBool = Boolean(left.photo_consent)
      const rightBool = Boolean(right.photo_consent)

      switch (sortConfig.key) {
        case 'age': {
          const a = Number(left.age ?? 0)
          const b = Number(right.age ?? 0)
          return (a - b) * dir
        }
        case 'photo_consent':
          return (Number(leftBool) - Number(rightBool)) * dir
        case 'school_id':
        case 'firstname':
        case 'lastname':
        case 'gender': {
          const a = String(left[sortConfig.key] ?? '').toLowerCase()
          const b = String(right[sortConfig.key] ?? '').toLowerCase()
          return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) * dir
        }
      }
    })
  }

  return (
    <AdminParityShell title="Classes Lists">
      {message ? <div className="alert alert-success">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <form
        className="row g-2 align-items-center justify-content-center mb-3"
        onSubmit={(event) => {
          event.preventDefault()
          void load(selectedYear)
        }}
      >
        <div className="col-auto">
          <label className="form-label mb-0">School year</label>
        </div>
        <div className="col-auto">
          <select
            className="form-select form-select-sm"
            style={{ minWidth: 200 }}
            value={selectedYear || defaultYear}
            onChange={(event) => setSelectedYear(event.target.value)}
          >
            {options.map((year) => (
              <option key={year.value} value={year.value}>{year.label}</option>
            ))}
          </select>
        </div>
        <div className="col-auto d-flex gap-2">
          <button type="submit" className="btn btn-secondary btn-sm">Apply</button>
          <button type="button" className="btn btn-outline-secondary btn-sm" onClick={() => void load(null)}>Reset</button>
        </div>
      </form>
      {loading ? (
        <p className="text-muted px-1">Loading class sections…</p>
      ) : sections.length === 0 ? (
        <p className="text-muted px-1">No class sections available.</p>
      ) : (
        <div id="classAccordion" className="d-flex flex-column gap-2">
          {sections.map((section, index) => {
            const key = String(index)
            const expanded = expandedSections.has(key)
            const students = section.students ?? []
            const displayedStudents = sortedStudents(students)
            const mainTeachers =
              section.main_teachers ?? section.mainTeachers ?? []
            const teacherAssistants =
              section.teacher_assistants ?? section.teacherAssistants ?? []
            return (
              <div key={key} className="card border-0 shadow-sm rounded-3">
                <div
                  className="card-header bg-white d-flex align-items-center justify-content-between rounded-3"
                  role="button"
                  style={{ cursor: 'pointer', userSelect: 'none' }}
                  onClick={() => toggleSection(key)}
                >
                  <div className="d-flex flex-column">
                    <span className="fw-semibold">
                      {expanded ? '▼' : '▶'}&nbsp;&nbsp;Grade : {section.class_section_name ?? 'Class'}
                    </span>
                    <span className="small text-muted">
                      Teacher: {mainTeachers.length > 0 ? mainTeachers.join(', ') : 'None'}
                      {' '}| TA: {teacherAssistants.length > 0 ? teacherAssistants.join(', ') : 'None'}
                    </span>
                  </div>
                  <span className="badge bg-secondary rounded-pill">{students.length}</span>
                </div>
                {expanded && (
                  <div className="card-body">
                    <h5>
                      Main Teacher:{' '}
                      {mainTeachers.length > 0
                        ? mainTeachers.join(', ')
                        : 'None'}
                    </h5>
                    <h5>
                      Teacher-Assistant:{' '}
                      {teacherAssistants.length > 0
                        ? teacherAssistants.join(', ')
                        : 'None'}
                    </h5>
                    <h5>Semester: {selectedSemester || 'N/A'}</h5>
                    <h5>School Year: {section.school_year ?? selectedYear ?? 'N/A'}</h5>
                    <p>{section.description ?? ''}</p>

                    {students.length > 0 ? (
                      <div className="table-responsive">
                        <table className="table table-bordered table-striped align-middle">
                          <thead className="table-light">
                            <tr>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('school_id')}>
                                  School ID {sortIndicator('school_id')}
                                </button>
                              </th>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('firstname')}>
                                  First Name {sortIndicator('firstname')}
                                </button>
                              </th>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('lastname')}>
                                  Last Name {sortIndicator('lastname')}
                                </button>
                              </th>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('age')}>
                                  Age {sortIndicator('age')}
                                </button>
                              </th>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('gender')}>
                                  Gender {sortIndicator('gender')}
                                </button>
                              </th>
                              <th>
                                <button type="button" className="btn btn-link btn-sm p-0 text-decoration-none" onClick={() => requestSort('photo_consent')}>
                                  Photo Consent {sortIndicator('photo_consent')}
                                </button>
                              </th>
                            </tr>
                          </thead>
                          <tbody>
                            {displayedStudents.map((student, studentIndex) => (
                              <tr key={`${section.class_section_id ?? index}-${student.id ?? studentIndex}`}>
                                <td>{student.school_id ?? '—'}</td>
                                <td>{student.firstname ?? '—'}</td>
                                <td>{student.lastname ?? '—'}</td>
                                <td>{student.age ?? '—'}</td>
                                <td>{student.gender ?? '—'}</td>
                                <td>
                                  <span className={`badge ${student.photo_consent ? 'bg-success' : 'bg-danger'}`}>
                                    {student.photo_consent ? 'Yes' : 'No'}
                                  </span>
                                </td>
                              </tr>
                            ))}
                          </tbody>
                        </table>
                      </div>
                    ) : (
                      <p>No students registered in this class section.</p>
                    )}
                  </div>
                )}
              </div>
            )
          })}
        </div>
      )}
    </AdminParityShell>
  )
}

export function AdminClassSectionPage() {
  const [sections, setSections] = useState<ClassSectionRow[]>([])
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)
  const [editingId, setEditingId] = useState<number | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [message, setMessage] = useState<string | null>(null)
  const [search, setSearch] = useState('')
  const [form, setForm] = useState({
    class_id: '',
    class_section_id: '',
    class_section_name: '',
    semester: '',
    school_year: '',
  })

  async function load(searchValue = '') {
    setLoading(true)
    try {
      const data = await fetchClassSections({ search: searchValue || undefined, perPage: 100 })
      setSections(data.data?.sections ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load class sections.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load('')
  }, [])

  function startEdit(row: ClassSectionRow) {
    setEditingId(row.id)
    setForm({
      class_id: String(row.class_id ?? ''),
      class_section_id: String(row.class_section_id ?? ''),
      class_section_name: row.class_section_name ?? '',
      semester: row.semester ?? '',
      school_year: row.school_year ?? '',
    })
  }

  function resetForm() {
    setEditingId(null)
    setForm({
      class_id: '',
      class_section_id: '',
      class_section_name: '',
      semester: '',
      school_year: '',
    })
  }

  async function submit(event: FormEvent) {
    event.preventDefault()
    setSaving(true)
    setMessage(null)
    setError(null)
    try {
      const payload = {
        class_id: Number(form.class_id),
        class_section_id: Number(form.class_section_id),
        class_section_name: form.class_section_name,
        semester: form.semester,
        school_year: form.school_year,
      }
      if (editingId) {
        await updateClassSection(editingId, payload)
        setMessage('Class section updated.')
      } else {
        await createClassSection(payload)
        setMessage('Class section created.')
      }
      resetForm()
      await load(search)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to save class section.')
    } finally {
      setSaving(false)
    }
  }

  async function remove(sectionId: number) {
    if (!window.confirm('Delete this class section?')) return
    await deleteClassSection(sectionId)
    await load(search)
  }

  return (
    <AdminParityShell title="Classes">
      {message ? <div className="alert alert-success">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="card mb-4">
        <div className="card-header">{editingId ? 'Edit Class' : 'Add New Class'}</div>
        <div className="card-body">
          <form className="row g-3" onSubmit={submit}>
            <div className="col-md-3">
              <label className="form-label">Class ID</label>
              <input className="form-control" value={form.class_id} onChange={(event) => setForm((current) => ({ ...current, class_id: event.target.value }))} required />
            </div>
            <div className="col-md-3">
              <label className="form-label">Section ID</label>
              <input className="form-control" value={form.class_section_id} onChange={(event) => setForm((current) => ({ ...current, class_section_id: event.target.value }))} required />
            </div>
            <div className="col-md-3">
              <label className="form-label">Name</label>
              <input className="form-control" value={form.class_section_name} onChange={(event) => setForm((current) => ({ ...current, class_section_name: event.target.value }))} required />
            </div>
            <div className="col-md-1">
              <label className="form-label">Semester</label>
              <input className="form-control" value={form.semester} onChange={(event) => setForm((current) => ({ ...current, semester: event.target.value }))} required />
            </div>
            <div className="col-md-2">
              <label className="form-label">School Year</label>
              <input className="form-control" value={form.school_year} onChange={(event) => setForm((current) => ({ ...current, school_year: event.target.value }))} required />
            </div>
            <div className="col-12 d-flex gap-2 justify-content-end">
              {editingId ? <button type="button" className="btn btn-secondary" onClick={resetForm}>Cancel</button> : null}
              <button className="btn btn-primary" type="submit" disabled={saving}>
                {saving ? 'Saving…' : editingId ? 'Update Class' : 'Create Class'}
              </button>
            </div>
          </form>
        </div>
      </div>

      <div className="d-flex justify-content-end mb-3">
        <div className="input-group" style={{ maxWidth: 340 }}>
          <input className="form-control" value={search} onChange={(event) => setSearch(event.target.value)} placeholder="Search class sections" />
          <button className="btn btn-outline-secondary" type="button" onClick={() => void load(search)}>
            Search
          </button>
        </div>
      </div>

      <div className="table-responsive">
        <table className="table table-striped align-middle">
          <thead>
            <tr>
              <th>ID</th>
              <th>Class ID</th>
              <th>Section ID</th>
              <th>Name</th>
              <th>Semester</th>
              <th>School Year</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={7} className="text-muted">Loading classes…</td></tr>
            ) : sections.length === 0 ? (
              <tr><td colSpan={7} className="text-muted">No class sections found.</td></tr>
            ) : (
              sections.map((row) => (
                <tr key={row.id}>
                  <td>{row.id}</td>
                  <td>{row.class_id ?? '—'}</td>
                  <td>{row.class_section_id ?? '—'}</td>
                  <td>{row.class_section_name ?? '—'}</td>
                  <td>{row.semester ?? '—'}</td>
                  <td>{row.school_year ?? '—'}</td>
                  <td className="d-flex gap-2">
                    <button className="btn btn-warning btn-sm" type="button" onClick={() => startEdit(row)}>
                      Edit
                    </button>
                    <button className="btn btn-danger btn-sm" type="button" onClick={() => void remove(row.id)}>
                      Delete
                    </button>
                  </td>
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminDailyAttendancePage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const semesterParam = searchParams.get('semester') ?? ''
  const schoolYearParam = searchParams.get('school_year') ?? ''
  const [data, setData] = useState<Awaited<ReturnType<typeof fetchAdministratorDailyAttendance>> | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [studentSearch, setStudentSearch] = useState('')
  const [tableSearch, setTableSearch] = useState('')
  const [activeGradeKey, setActiveGradeKey] = useState<string>('')
  const [activeSectionId, setActiveSectionId] = useState<string>('')
  const [termFilters, setTermFilters] = useState(() => ({
    semester: semesterParam.trim() === 'Spring' ? 'Spring' : 'Fall',
    school_year: schoolYearParam,
  }))
  const [pageSize, setPageSize] = useState(100)
  const [datePageIndex, setDatePageIndex] = useState(0)
  const [busyKey, setBusyKey] = useState<string | null>(null)
  const [actionMessage, setActionMessage] = useState<string | null>(null)

  useEffect(() => {
    if (!actionMessage) return
    const t = window.setTimeout(() => setActionMessage(null), 2500)
    return () => window.clearTimeout(t)
  }, [actionMessage])

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const result = await fetchAdministratorDailyAttendance({
          semester: semesterParam || null,
          schoolYear: schoolYearParam || null,
        })
        if (cancelled) return
        setData(result)
        const apiSchoolYear = result.school_year != null ? String(result.school_year).trim() : ''
        const apiSemester = result.semester != null ? String(result.semester).trim() : ''
        setTermFilters((current) => ({
          school_year: schoolYearParam.trim() || current.school_year.trim() || apiSchoolYear,
          semester:
            semesterParam.trim() === 'Spring'
              ? 'Spring'
              : semesterParam.trim() === 'Fall'
                ? 'Fall'
                : apiSemester === 'Spring' || apiSemester === 'Fall'
                  ? apiSemester
                  : current.semester === 'Spring'
                    ? 'Spring'
                    : 'Fall',
        }))
        const sections = buildAttendanceSections(result)
        const groups = buildAttendanceGradeGroups(sections)
        setActiveGradeKey(groups[0]?.key ?? '')
        setActiveSectionId(sections[0]?.sectionId ?? '')
        setError(null)
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load attendance.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [schoolYearParam, semesterParam])

  useEffect(() => {
    setTermFilters((current) => ({
      school_year: schoolYearParam.trim() || current.school_year,
      semester:
        semesterParam.trim() === 'Spring'
          ? 'Spring'
          : semesterParam.trim() === 'Fall'
            ? 'Fall'
            : current.semester === 'Spring'
              ? 'Spring'
              : 'Fall',
    }))
  }, [schoolYearParam, semesterParam])

  const sections = useMemo(() => (data ? buildAttendanceSections(data) : []), [data])
  const gradeGroups = useMemo(() => buildAttendanceGradeGroups(sections), [sections])
  const normalizedSearch = normalizeAttendanceSearch(studentSearch)
  const searchMatches = useMemo(() => {
    if (normalizedSearch === '') return []
    return sections.flatMap((section) =>
      section.students
        .filter((student) => {
          return attendanceSearchMatchesPrefix(normalizedSearch, [
            student.schoolId,
            student.name,
            `${student.schoolId} ${student.name}`,
            `${student.name} ${student.schoolId}`,
            `${student.name} ${section.className}`,
          ])
        })
        .map((student) => ({
          section,
          student,
        })),
    )
  }, [normalizedSearch, sections])
  const selectedSearchMatch = searchMatches[0] ?? null
  const displayedGrade = gradeGroups.find((group) => group.key === activeGradeKey) ?? gradeGroups[0]
  const gradeSections = displayedGrade?.sections ?? []
  const displayedSection =
    gradeSections.find((row) => row.sectionId === activeSectionId) ??
    gradeSections[0] ??
    sections.find((row) => row.sectionId === activeSectionId) ??
    sections[0]
  const sectionFilter = normalizeAttendanceSearch(tableSearch)
  const renderedStudents = useMemo<AttendanceRenderedStudentRow[]>(() => {
    if (normalizedSearch !== '') {
      const seen = new Set<string>()
      return searchMatches.flatMap((match) => {
        const key = `${match.section.sectionId}:${match.student.id}`
        if (seen.has(key)) return []
        seen.add(key)
        return [{
          sectionId: match.section.sectionId,
          sectionName: match.section.className,
          student: match.student,
        }]
      })
    }

    if (!displayedSection) return []

    return displayedSection.students
      .filter((student) => {
        if (sectionFilter === '') return true
        return attendanceSearchMatchesPrefix(sectionFilter, [
          student.schoolId,
          student.name,
          `${student.schoolId} ${student.name}`,
          `${student.name} ${student.schoolId}`,
          `${student.name} ${displayedSection.className}`,
        ])
      })
      .map((student) => ({
        sectionId: displayedSection.sectionId,
        sectionName: displayedSection.className,
        student,
      }))
  }, [displayedSection, normalizedSearch, searchMatches, sectionFilter])
  const allVisibleDates = useMemo(() => {
    if (normalizedSearch !== '') {
      const set = new Set<string>()
      for (const match of searchMatches) {
        for (const date of match.section.dates) set.add(date)
      }
      return Array.from(set).sort()
    }
    return displayedSection?.dates ?? []
  }, [displayedSection, normalizedSearch, searchMatches])

  const allDates = useMemo(() => {
    const recorded = new Set(allVisibleDates)
    const semesterDates = Array.isArray(data?.date_list) ? data.date_list as string[] : []
    let coming: string[]
    if (semesterDates.length > 0) {
      // Show all semester Sundays not yet recorded, including no-school days (they'll be flagged visually)
      coming = semesterDates.filter((d) => !recorded.has(d))
    } else {
      const today = new Date().toISOString().slice(0, 10)
      const anchor = allVisibleDates.length > 0
        ? allVisibleDates[allVisibleDates.length - 1]
        : today
      coming = []
      let cur = nextSundayAfter(anchor)
      while (cur && coming.length < 20) {
        if (!recorded.has(cur)) coming.push(cur)
        cur = nextSundayAfter(cur)
      }
    }
    return [...allVisibleDates, ...coming].sort()
  }, [allVisibleDates, data?.date_list])

  const noSchoolDays: Record<string, string> = data?.no_school_days ?? {}

  const DATE_PAGE_SIZE = 5
  const datePageCount = Math.max(1, Math.ceil(allDates.length / DATE_PAGE_SIZE))
  const clampedDatePage = Math.min(datePageIndex, datePageCount - 1)
  const visibleDates = allDates.slice(
    clampedDatePage * DATE_PAGE_SIZE,
    clampedDatePage * DATE_PAGE_SIZE + DATE_PAGE_SIZE,
  )
  const visibleStudents = useMemo(() => {
    return renderedStudents.filter(({ student, sectionName }) => {
      if (sectionFilter === '') return true
      return attendanceSearchMatchesPrefix(sectionFilter, [
        student.schoolId,
        student.name,
        `${student.schoolId} ${student.name}`,
        `${student.name} ${student.schoolId}`,
        `${student.name} ${sectionName}`,
      ])
    })
  }, [renderedStudents, sectionFilter])

  const tableRows = useMemo(() => visibleStudents.slice(0, pageSize), [visibleStudents, pageSize])
  const tableEmptyColSpan = 1 + (normalizedSearch !== '' ? 1 : 0) + 1 + visibleDates.length + 4

  const schoolYearOptions = useMemo(() => {
    const set = new Set<string>()
    for (const y of [termFilters.school_year, data?.school_year != null ? String(data.school_year) : '']) {
      const t = String(y).trim()
      if (t) set.add(t)
    }
    return Array.from(set).sort()
  }, [termFilters.school_year, data?.school_year])

  useEffect(() => {
    if (!displayedGrade) return
    if (!gradeSections.some((section) => section.sectionId === activeSectionId)) {
      setActiveSectionId(displayedGrade.sections[0]?.sectionId ?? '')
    }
  }, [activeSectionId, displayedGrade, gradeSections])

  useEffect(() => {
    setDatePageIndex(Number.MAX_SAFE_INTEGER)
  }, [activeSectionId, activeGradeKey, normalizedSearch])

  async function persistAttendanceCell(
    section: AttendanceSectionSnapshot,
    student: AttendanceSectionSnapshot['students'][number],
    date: string,
    raw: string,
  ) {
    const cellKey = `${section.sectionId}-${student.id}-${date}`
    if (raw === '') return
    let status: 'present' | 'absent' | 'late'
    let is_reported: string | null = null
    if (raw === 'present') status = 'present'
    else if (raw === 'absent') status = 'absent'
    else if (raw === 'absent_reported') {
      status = 'absent'
      is_reported = 'yes'
    } else if (raw === 'late_reported') {
      status = 'late'
      is_reported = 'yes'
    } else if (raw === 'late') {
      status = 'late'
      is_reported = 'no'
    } else {
      return
    }

    const semesterVal = String(data?.semester ?? semesterParam ?? '').trim()
    const schoolYearVal = String(data?.school_year ?? schoolYearParam ?? '').trim()

    // Optimistic update — patch local data immediately so the UI reflects the change at once
    const prevData = data
    setData((current) => {
      if (!current) return current
      const secId = String(section.sectionId)
      const stuId = String(student.id)
      const prevEntries = JSON.parse(
        JSON.stringify(current.attendance_data ?? {}),
      ) as NonNullable<typeof current.attendance_data>
      if (!prevEntries[secId]) prevEntries[secId] = {}
      const existing = (prevEntries[secId][stuId] ?? []).filter((e) => String(e.date ?? '').slice(0, 10) !== date)
      prevEntries[secId][stuId] = [
        ...existing,
        { date, status, reason: null, is_reported: is_reported ?? 'no' },
      ]
      return { ...current, attendance_data: prevEntries }
    })

    setBusyKey(cellKey)
    setError(null)
    try {
      await updateAdministratorAttendance({
        class_section_id: Number(section.sectionId),
        student_id: student.id,
        school_id: student.schoolId && student.schoolId !== '—' ? student.schoolId : null,
        status,
        date,
        class_id: section.classId,
        semester: semesterVal || null,
        school_year: schoolYearVal || null,
        is_reported: (status === 'late' || status === 'absent') ? is_reported : null,
      })
      setActionMessage('Saved.')
    } catch (e) {
      setData(prevData)
      setError(e instanceof Error ? e.message : 'Unable to save attendance.')
    } finally {
      setBusyKey(null)
    }
  }

  return (
    <AdminParityShell title="Attendance Management" showTitle={false}>
      <div className="att-mgmt-page">
        <div className="text-center mb-4">
          <h1 className="att-mgmt-hero-title mb-0">Attendance Management</h1>
        </div>

        <form
          className="att-mgmt-filter-bar row g-3 justify-content-center align-items-end mb-4"
          onSubmit={(event) => {
            event.preventDefault()
            const next = new URLSearchParams()
            if (termFilters.school_year.trim() !== '') next.set('school_year', termFilters.school_year.trim())
            if (termFilters.semester.trim() !== '') next.set('semester', termFilters.semester.trim())
            setSearchParams(next)
          }}
        >
          <div className="col-12 col-sm-auto">
            <label className="form-label">School year</label>
            <select
              className="form-select"
              value={termFilters.school_year}
              onChange={(event) => setTermFilters((current) => ({ ...current, school_year: event.target.value }))}
            >
              {schoolYearOptions.length === 0 ? (
                <option value="">{loading ? 'Loading…' : '—'}</option>
              ) : (
                schoolYearOptions.map((year) => (
                  <option key={year} value={year}>
                    {year}
                  </option>
                ))
              )}
            </select>
          </div>
          <div className="col-12 col-sm-auto">
            <label className="form-label">Semester</label>
            <select
              className="form-select"
              value={termFilters.semester === 'Spring' ? 'Spring' : 'Fall'}
              onChange={(event) => setTermFilters((current) => ({ ...current, semester: event.target.value }))}
            >
              <option value="Fall">Fall</option>
              <option value="Spring">Spring</option>
            </select>
          </div>
          <div className="col-12 col-sm-auto d-flex flex-wrap gap-2">
            <button className="btn att-btn-apply" type="submit">
              Apply
            </button>
            <button
              className="btn btn-outline-secondary"
              type="button"
              onClick={() => {
                setTermFilters({ semester: 'Fall', school_year: '' })
                setSearchParams(new URLSearchParams())
              }}
            >
              Reset
            </button>
          </div>
        </form>

        <div className="row g-2 justify-content-center mb-4">
          <div className="col-12 col-lg-8">
            <div className="input-group att-search-wrap">
              <span className="input-group-text">Search Student</span>
              <input
                className="form-control"
                type="text"
                placeholder="Type School ID or Student Name"
                value={studentSearch}
                onChange={(event) => setStudentSearch(event.target.value)}
              />
              <button className="btn btn-outline-secondary" type="button" onClick={() => setStudentSearch('')}>
                Clear
              </button>
            </div>
            <small className="text-muted">Searches all grades.</small>
            {normalizedSearch !== '' ? (
              <div className={`small mt-1 ${searchMatches.length > 0 ? 'text-success' : 'text-danger'}`}>
                {searchMatches.length > 0
                  ? `${searchMatches.length} match${searchMatches.length === 1 ? '' : 'es'} found.${
                      selectedSearchMatch ? ` First match: ${selectedSearchMatch.section.className}.` : ''
                    }`
                  : 'No student matched the current search.'}
              </div>
            ) : null}
            {normalizedSearch !== '' && searchMatches.length > 0 ? (
              <div className="list-group mt-2" style={{ maxHeight: 240, overflowY: 'auto' }}>
                {searchMatches.slice(0, 12).map((match) => (
                  <button
                    key={`${match.section.sectionId}-${match.student.id}`}
                    type="button"
                    className="list-group-item list-group-item-action"
                    onClick={() => {
                      setActiveGradeKey(
                        gradeGroups.find((group) =>
                          group.sections.some((section) => section.sectionId === match.section.sectionId),
                        )?.key ?? '',
                      )
                      setActiveSectionId(match.section.sectionId)
                    }}
                  >
                    <div className="fw-semibold">
                      {match.student.schoolId} - {match.student.name}
                    </div>
                    <div className="small text-muted">{match.section.className}</div>
                  </button>
                ))}
              </div>
            ) : null}
          </div>
        </div>

        <div className="text-center mb-4">
          <Link className="btn btn-outline-primary att-btn-analysis" to="/app/administrator/daily_attendance_analysis">
            Attendance Analysis
          </Link>
        </div>

        {actionMessage ? <div className="alert alert-success py-2 text-center">{actionMessage}</div> : null}
        {error ? <div className="alert alert-danger">{error}</div> : null}
        {loading ? (
          <p className="text-muted text-center">Loading attendance…</p>
        ) : sections.length === 0 ? (
          <p className="text-muted text-center">No attendance sections found.</p>
        ) : (
          <>
            <div className="att-grade-tabs mb-3" role="tablist" aria-label="Grade">
              {gradeGroups.map((group) => {
                const count = group.sections.reduce((acc, section) => acc + section.students.length, 0)
                const active = group.key === displayedGrade?.key
                return (
                  <button
                    key={group.key}
                    type="button"
                    role="tab"
                    aria-selected={active}
                    className={`att-grade-tab ${active ? 'active' : ''}`}
                    onClick={() => setActiveGradeKey(group.key)}
                  >
                    <span className="att-dot" aria-hidden="true" />
                    <span>{group.label}</span>
                    <span className="att-count">{count}</span>
                  </button>
                )
              })}
            </div>

            {gradeSections.length > 1 ? (
              <div className="att-section-pills mb-3">
                {gradeSections.map((section) => (
                  <button
                    key={section.sectionId}
                    type="button"
                    className={`btn btn-sm ${section.sectionId === displayedSection?.sectionId ? 'btn-primary' : 'btn-outline-secondary'}`}
                    onClick={() => setActiveSectionId(section.sectionId)}
                  >
                    {section.className}
                  </button>
                ))}
              </div>
            ) : null}

            {displayedSection ? (
              <>
                <div className="text-center mb-3">
                  <h2 className="att-section-heading mb-3">
                    {normalizedSearch !== '' ? 'Search Results' : displayedSection.className}
                  </h2>
                  <div className="d-flex justify-content-center align-items-center gap-3 att-date-range">
                    <button
                      type="button"
                      className="btn btn-primary att-date-nav"
                      disabled={clampedDatePage === 0}
                      onClick={() => setDatePageIndex(clampedDatePage - 1)}
                    >
                      ‹
                    </button>
                    <span>
                      {visibleDates[0] ? formatAttendanceMdY(visibleDates[0]) : '—'}
                      {visibleDates.length > 1
                        ? ` — ${formatAttendanceMdY(visibleDates[visibleDates.length - 1])}`
                        : ''}
                    </span>
                    <button
                      type="button"
                      className="btn btn-primary att-date-nav"
                      disabled={clampedDatePage >= datePageCount - 1}
                      onClick={() => setDatePageIndex(clampedDatePage + 1)}
                    >
                      ›
                    </button>
                  </div>
                </div>

                <div className="d-flex flex-wrap justify-content-between align-items-center gap-3 mb-2 att-table-toolbar">
                  <div className="d-flex align-items-center gap-2">
                    <span>Show</span>
                    <select
                      className="form-select form-select-sm"
                      style={{ width: 78 }}
                      value={pageSize}
                      onChange={(event) => setPageSize(Number(event.target.value))}
                    >
                      {[25, 50, 100, 200].map((n) => (
                        <option key={n} value={n}>
                          {n}
                        </option>
                      ))}
                    </select>
                    <span>entries</span>
                  </div>
                  <div className="d-flex align-items-center gap-2">
                    <label className="mb-0">Search:</label>
                    <input
                      className="form-control form-control-sm"
                      style={{ width: 220 }}
                      value={tableSearch}
                      onChange={(event) => setTableSearch(event.target.value)}
                    />
                  </div>
                </div>

                <div className="table-responsive">
                  <table className="table table-bordered table-striped align-middle att-mgmt-table">
                    <thead className="att-mgmt-thead">
                      <tr>
                        <th className="school-id-col">School ID</th>
                        {normalizedSearch !== '' ? <th>Section</th> : null}
                        <th className="student-name-col">Student Name</th>
                        {visibleDates.map((date) => {
                          const noSchoolTitle = noSchoolDays[date]
                          return (
                            <th
                              key={date}
                              className={`date-col${noSchoolTitle ? ' table-info' : ''}`}
                              title={noSchoolTitle ?? undefined}
                            >
                              {formatAttendanceMdY(date)}
                              {noSchoolTitle ? <div style={{ fontSize: '0.7rem', fontWeight: 400 }}>{noSchoolTitle}</div> : null}
                            </th>
                          )
                        })}
                        <th className="text-center">P</th>
                        <th className="text-center">L</th>
                        <th className="text-center">A</th>
                        <th className="text-center">T</th>
                      </tr>
                    </thead>
                    <tbody>
                      {tableRows.map(({ sectionId, sectionName, student }) => {
                        const sectionSnap = sections.find((s) => s.sectionId === sectionId)
                        if (!sectionSnap) return null
                        return (
                          <tr key={`${sectionId}-${student.id}`}>
                            <td className="school-id-col">{student.schoolId}</td>
                            {normalizedSearch !== '' ? <td>{sectionName}</td> : null}
                            <td className="student-name-col">{student.name}</td>
                            {visibleDates.map((date) => {
                              const noSchoolTitle = noSchoolDays[date]
                              const entry = student.entriesByDate[date]
                              const cellVal = entryToAttendanceSelectValue(entry)
                              const cellBusy = busyKey === `${sectionId}-${student.id}-${date}`
                              return (
                                <td key={date} className={`date-col${noSchoolTitle ? ' table-info' : ''}`}>
                                  <select
                                    className={attendanceCellSelectClass(cellVal)}
                                    value={cellVal}
                                    disabled={cellBusy || loading || !!noSchoolTitle}
                                    onChange={(event) => {
                                      void persistAttendanceCell(sectionSnap, student, date, event.target.value)
                                    }}
                                  >
                                    <option value="">Select attendance</option>
                                    <option value="present">Present</option>
                                    <option value="late">Late</option>
                                    <option value="late_reported">Late — Reported</option>
                                    <option value="absent">Absent</option>
                                    <option value="absent_reported">Absent — Reported</option>
                                  </select>
                                </td>
                              )
                            })}
                            <td className="att-summary-col">{student.summary.present}</td>
                            <td className="att-summary-col">{student.summary.late}</td>
                            <td className="att-summary-col">{student.summary.absent}</td>
                            <td className="att-summary-col">{student.summary.total}</td>
                          </tr>
                        )
                      })}
                      {tableRows.length === 0 ? (
                        <tr>
                          <td colSpan={tableEmptyColSpan} className="text-muted text-center">
                            No students match the current search.
                          </td>
                        </tr>
                      ) : null}
                    </tbody>
                  </table>
                </div>
              </>
            ) : null}
          </>
        )}
      </div>
    </AdminParityShell>
  )
}

export function AdminDailyAttendanceAnalysisPage() {
  const [data, setData] = useState<Awaited<ReturnType<typeof fetchAdministratorDailyAttendance>> | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const result = await fetchAdministratorDailyAttendance()
        if (cancelled) return
        setData(result)
        setError(null)
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load attendance analysis.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [])

  const sections = useMemo(() => (data ? buildAttendanceSections(data) : []), [data])
  const analysis = useMemo(() => buildAttendanceAnalysis(sections), [sections])
  const total = analysis.overall.present + analysis.overall.late + analysis.overall.absent

  return (
    <AdminParityShell title="Attendance Analysis">
      <div className="d-flex justify-content-end mb-3">
        <Link className="btn btn-outline-secondary" to="/app/administrator/daily_attendance">
          Back to Attendance
        </Link>
      </div>
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted">Loading analysis…</p>
      ) : (
        <div className="row g-3">
          <div className="col-md-4">
            <div className="card h-100">
              <div className="card-body">
                <h5 className="card-title">Overall</h5>
                <p className="mb-2">Present: {analysis.overall.present}</p>
                <p className="mb-2">Late: {analysis.overall.late}</p>
                <p className="mb-0">Absent: {analysis.overall.absent}</p>
                <hr />
                <p className="mb-0 small text-muted">Total attendance marks: {total}</p>
              </div>
            </div>
          </div>

          <div className="col-md-8">
            <div className="card h-100">
              <div className="card-body">
                <h5 className="card-title">By Class</h5>
                <div className="table-responsive">
                  <table className="table table-sm align-middle mb-0">
                    <thead>
                      <tr>
                        <th>Class</th>
                        <th>Students</th>
                        <th>Present</th>
                        <th>Late</th>
                        <th>Absent</th>
                      </tr>
                    </thead>
                    <tbody>
                      {analysis.byClass.map(([className, row]) => (
                        <tr key={className}>
                          <td>{className}</td>
                          <td>{row.totalStudents}</td>
                          <td>{row.present}</td>
                          <td>{row.late}</td>
                          <td>{row.absent}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>

          <div className="col-12">
            <div className="card">
              <div className="card-body">
                <h5 className="card-title">Students Needing Attention</h5>
                <div className="table-responsive">
                  <table className="table table-striped align-middle mb-0">
                    <thead>
                      <tr>
                        <th>Student</th>
                        <th>School ID</th>
                        <th>Class</th>
                        <th>Absent</th>
                        <th>Late</th>
                      </tr>
                    </thead>
                    <tbody>
                      {analysis.studentsNeedingAttention.length === 0 ? (
                        <tr><td colSpan={5} className="text-muted">No absences or tardies recorded.</td></tr>
                      ) : (
                        analysis.studentsNeedingAttention.slice(0, 50).map((student) => (
                          <tr key={`${student.schoolId}-${student.name}`}>
                            <td>{student.name}</td>
                            <td>{student.schoolId}</td>
                            <td>{student.className}</td>
                            <td>{student.absent}</td>
                            <td>{student.late}</td>
                          </tr>
                        ))
                      )}
                    </tbody>
                  </table>
                </div>
              </div>
            </div>
          </div>
        </div>
      )}
    </AdminParityShell>
  )
}

export function AdminExamDraftsPage() {
  const [data, setData] = useState<Awaited<ReturnType<typeof fetchExamDraftAdminData>> | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [message, setMessage] = useState<string | null>(null)
  const [activeTab, setActiveTab] = useState<'submissions' | 'legacy'>('submissions')
  const [legacyFile, setLegacyFile] = useState<File | null>(null)
  const [legacyForm, setLegacyForm] = useState({
    class_section_id: '',
    school_year: '',
    semester: '',
    exam_type: '',
  })
  const [reviewState, setReviewState] = useState<Record<number, { review_status: string; admin_comments: string; final_file: File | null }>>({})

  async function load() {
    try {
      const result = await fetchExamDraftAdminData()
      setData(result)
      setLegacyForm((current) => ({
        ...current,
        school_year: current.school_year || result.school_year || '',
        semester: current.semester || result.semester || '',
      }))
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load exam drafts.')
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function submitLegacy(event: FormEvent) {
    event.preventDefault()
    if (!legacyForm.class_section_id) {
      setError('Select a class section before uploading a legacy exam.')
      return
    }
    if (!legacyFile) {
      setError('Choose a file to upload.')
      return
    }
    try {
      setError(null)
      const result = await uploadLegacyExamDraft({
        class_section_id: Number(legacyForm.class_section_id),
        school_year: legacyForm.school_year,
        semester: legacyForm.semester,
        exam_type: legacyForm.exam_type || undefined,
        old_exam_file: legacyFile,
      })
      setMessage(result.message ?? 'Legacy exam uploaded.')
      setLegacyFile(null)
      await load()
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to upload legacy exam.')
    }
  }

  async function submitReview(draft: ExamDraftRow) {
    const row = reviewState[draft.id] ?? { review_status: '', admin_comments: '', final_file: null }
    try {
      const result = await reviewExamDraft({
        draft_id: draft.id,
        review_status: row.review_status || undefined,
        admin_comments: row.admin_comments || undefined,
        final_file: row.final_file,
      })
      setMessage(result.message ?? 'Draft review updated.')
      await load()
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to review draft.')
    }
  }

  const teacherFilePath = (name?: string | null) => (name ? `/api/v1/files/exams/teacher/${encodeURIComponent(name)}` : null)
  const finalFilePath = (name?: string | null) => (name ? `/api/v1/files/exams/final/${encodeURIComponent(name)}` : null)
  const allowedExtensions = data?.allowed_extensions ?? ['doc', 'docx', 'pdf']
  const maxUploadMb = Math.max(1, Math.round((data?.max_upload_bytes ?? 12 * 1024 * 1024) / 1024 / 1024))
  const classSections = data?.class_sections ?? []
  const drafts = (data?.drafts ?? []).filter((draft) => !Boolean(draft.is_legacy))
  const legacyByClass = data?.legacy_by_class ?? {}

  const draftsByClass = useMemo(() => {
    const grouped = new Map<number, ExamDraftRow[]>()
    for (const draft of drafts) {
      const sectionId = Number(draft.class_section_id ?? 0)
      if (!sectionId) continue
      const rows = grouped.get(sectionId) ?? []
      rows.push(draft)
      grouped.set(sectionId, rows)
    }
    for (const rows of grouped.values()) {
      rows.sort((a, b) => {
        const aTime = String(a.reviewed_at ?? '')
        const bTime = String(b.reviewed_at ?? '')
        return bTime.localeCompare(aTime)
      })
    }
    return grouped
  }, [drafts])

  const visibleClasses = useMemo(() => {
    const base = classSections
      .map((section) => ({
        class_section_id: Number(section.class_section_id ?? 0),
        class_section_name: section.class_section_name ?? '',
      }))
      .filter((section) => section.class_section_id > 0)

    const seen = new Set<number>()
    const merged: Array<{ class_section_id: number; class_section_name: string }> = []

    for (const section of base) {
      if (seen.has(section.class_section_id)) continue
      seen.add(section.class_section_id)
      merged.push(section)
    }

    for (const draft of drafts) {
      const sectionId = Number(draft.class_section_id ?? 0)
      if (!sectionId || seen.has(sectionId)) continue
      seen.add(sectionId)
      merged.push({
        class_section_id: sectionId,
        class_section_name: draft.class_section_name ?? `Class ${sectionId}`,
      })
    }

    return merged.sort((a, b) => a.class_section_name.localeCompare(b.class_section_name))
  }, [classSections, drafts])

  function statusBadgeClass(status?: string | null): string {
    switch (String(status ?? '').toLowerCase()) {
      case 'submitted':
        return 'bg-warning text-dark'
      case 'reviewed':
        return 'bg-info text-dark'
      case 'finalized':
        return 'bg-success'
      case 'rejected':
        return 'bg-danger'
      default:
        return 'bg-secondary'
    }
  }

  return (
    <AdminParityShell title="Exam Draft Submissions">
      {message ? <div className="alert alert-success">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="d-flex flex-column flex-lg-row justify-content-between align-items-lg-center gap-3 mb-4">
        <div>
          <p className="text-muted mb-0 small">{data?.semester || 'Semester'} {data?.school_year || ''}</p>
        </div>
        <div className="text-muted small d-flex flex-column align-items-lg-end">
          <span>Allowed files: {allowedExtensions.join(', ')}</span>
          <span>Max size: {maxUploadMb} MB</span>
        </div>
      </div>

      <div className="card mb-3">
        <div className="card-body py-3 d-flex flex-column flex-md-row justify-content-between align-items-md-center gap-3">
          <div>
            <div className="fw-semibold">View</div>
            <div className="small text-muted">Switch between new draft submissions and legacy uploaded exams.</div>
          </div>
          <div className="btn-group" role="group" aria-label="Exam draft tabs">
            <button
              type="button"
              className={`btn ${activeTab === 'submissions' ? 'btn-primary' : 'btn-outline-primary'}`}
              onClick={() => setActiveTab('submissions')}
              aria-pressed={activeTab === 'submissions'}
            >
              Draft submissions
            </button>
            <button
              type="button"
              className={`btn ${activeTab === 'legacy' ? 'btn-primary' : 'btn-outline-primary'}`}
              onClick={() => setActiveTab('legacy')}
              aria-pressed={activeTab === 'legacy'}
            >
              Legacy exams
            </button>
          </div>
        </div>
      </div>

      {activeTab === 'submissions' ? (
        <div className="card mb-4">
          <div className="card-body">
            {visibleClasses.length === 0 ? (
              <p className="text-muted mb-0">No classes with enrolled students are available for this term.</p>
            ) : (
              <div className="accordion" id="examDraftsAccordion">
                {visibleClasses.map((section, index) => {
                  const sectionDrafts = draftsByClass.get(section.class_section_id) ?? []
                  const submittedCount = sectionDrafts.filter((draft) => String(draft.status ?? '').toLowerCase() === 'submitted').length
                  const collapseId = `examDraftGroup_${section.class_section_id}`
                  return (
                    <div className="accordion-item mb-3" key={section.class_section_id}>
                      <h2 className="accordion-header" id={`heading_${collapseId}`}>
                        <button
                          className={`accordion-button px-3 ${index === 0 ? '' : 'collapsed'}`}
                          type="button"
                          data-bs-toggle="collapse"
                          data-bs-target={`#${collapseId}`}
                          aria-expanded={index === 0}
                          aria-controls={collapseId}
                        >
                          <div className="d-flex flex-column flex-lg-row w-100 justify-content-between gap-2">
                            <div>
                              <strong>{section.class_section_name || `Class ${section.class_section_id}`}</strong>
                              <div className="small text-muted">Class section ID: {section.class_section_id}</div>
                            </div>
                            <div className="d-flex align-items-center gap-2 flex-wrap">
                              <span className={`badge ${submittedCount > 0 ? 'bg-warning text-dark' : 'bg-secondary'}`}>
                                New submissions: {submittedCount}
                              </span>
                              <span className="badge bg-light text-dark border">Total drafts: {sectionDrafts.length}</span>
                            </div>
                          </div>
                        </button>
                      </h2>
                      <div
                        id={collapseId}
                        className={`accordion-collapse collapse ${index === 0 ? 'show' : ''}`}
                        data-bs-parent="#examDraftsAccordion"
                      >
                        <div className="accordion-body">
                          {sectionDrafts.length === 0 ? (
                            <p className="text-muted mb-0">No submissions for this class yet.</p>
                          ) : (
                            <div className="table-responsive">
                              <table className="table table-bordered align-middle exam-drafts-table">
                                <thead className="table-light">
                                  <tr>
                                    <th>Teacher</th>
                                    <th>Title</th>
                                    <th>Type</th>
                                    <th>Version</th>
                                    <th>Status</th>
                                    <th>Files</th>
                                    <th>Review</th>
                                  </tr>
                                </thead>
                                <tbody>
                                  {sectionDrafts.map((draft) => {
                                    const teacherName = `${draft.teacher_first ?? ''} ${draft.teacher_last ?? ''}`.trim() || 'Admin upload'
                                    const state = reviewState[draft.id] ?? { review_status: draft.status ?? '', admin_comments: draft.admin_comments ?? '', final_file: null }
                                    const isFinalLegacy = Boolean(draft.is_legacy) && draft.status === 'finalized'
                                    const teacherPath = teacherFilePath(draft.teacher_file)
                                    const finalPath = finalFilePath(draft.final_pdf_file ?? draft.final_file)
                                    return (
                                      <tr key={draft.id}>
                                        <td>{teacherName}</td>
                                        <td>
                                          <div className="fw-semibold">{draft.draft_title ?? 'Untitled'}</div>
                                          <div className="small text-muted">{draft.description ?? ''}</div>
                                        </td>
                                        <td>{draft.exam_type ?? '—'}</td>
                                        <td>{draft.version ?? 1}</td>
                                        <td>
                                          <span className={`badge ${statusBadgeClass(draft.status)}`}>{draft.status ?? '—'}</span>
                                        </td>
                                        <td className="text-nowrap" style={{ minWidth: 220 }}>
                                          <div className="d-flex flex-wrap gap-2">
                                            {teacherPath ? (
                                              <button
                                                type="button"
                                                className="btn btn-sm btn-outline-secondary"
                                                onClick={() => void openProtectedApiFile(teacherPath)}
                                              >
                                                Teacher file
                                              </button>
                                            ) : null}
                                            {finalPath ? (
                                              <button
                                                type="button"
                                                className="btn btn-sm btn-outline-primary"
                                                onClick={() => void openProtectedApiFile(finalPath)}
                                              >
                                                Final file
                                              </button>
                                            ) : null}
                                          </div>
                                        </td>
                                        <td style={{ minWidth: 260 }}>
                                          {isFinalLegacy ? (
                                            <div className="text-muted small">Legacy upload is finalized automatically.</div>
                                          ) : (
                                            <div className="vstack gap-2">
                                              <select
                                                className="form-select form-select-sm"
                                                value={state.review_status}
                                                onChange={(event) =>
                                                  setReviewState((current) => ({
                                                    ...current,
                                                    [draft.id]: { ...state, review_status: event.target.value },
                                                  }))
                                                }
                                              >
                                                <option value="">Select status</option>
                                                {(data?.status_options ?? []).map((status) => (
                                                  <option key={status} value={status}>
                                                    {status}
                                                  </option>
                                                ))}
                                              </select>
                                              <textarea
                                                className="form-control form-control-sm"
                                                rows={2}
                                                value={state.admin_comments}
                                                onChange={(event) =>
                                                  setReviewState((current) => ({
                                                    ...current,
                                                    [draft.id]: { ...state, admin_comments: event.target.value },
                                                  }))
                                                }
                                                placeholder="Feedback for the teacher"
                                              />
                                              <input
                                                className="form-control form-control-sm"
                                                type="file"
                                                accept={allowedExtensions.map((ext) => `.${ext}`).join(',')}
                                                onChange={(event) =>
                                                  setReviewState((current) => ({
                                                    ...current,
                                                    [draft.id]: { ...state, final_file: event.target.files?.[0] ?? null },
                                                  }))
                                                }
                                              />
                                              <button
                                                className="btn btn-sm btn-outline-primary"
                                                type="button"
                                                onClick={() => void submitReview(draft)}
                                              >
                                                Save Review
                                              </button>
                                            </div>
                                          )}
                                        </td>
                                      </tr>
                                    )
                                  })}
                                </tbody>
                              </table>
                            </div>
                          )}
                        </div>
                      </div>
                    </div>
                  )
                })}
              </div>
            )}
          </div>
        </div>
      ) : (
        <>
          <div className="card border-primary-subtle mb-3">
            <div className="card-header bg-light d-flex justify-content-between align-items-center">
              <div>
                <strong>Upload old / legacy exam</strong>
                <div className="small text-muted">Store historic exams as accepted records.</div>
              </div>
              <span className="badge bg-primary-subtle text-primary">Admin only</span>
            </div>
            <div className="card-body">
              <form className="row g-3" onSubmit={submitLegacy}>
                <div className="col-md-4">
                  <label className="form-label small">Class section</label>
                  <select
                    className="form-select"
                    value={legacyForm.class_section_id}
                    onChange={(event) => setLegacyForm((current) => ({ ...current, class_section_id: event.target.value }))}
                    required
                  >
                    <option value="">Select class</option>
                    {classSections.map((section) => (
                      <option key={section.class_section_id} value={section.class_section_id}>
                        {section.class_section_name}
                      </option>
                    ))}
                  </select>
                </div>
                <div className="col-md-2">
                  <label className="form-label small">School year</label>
                  <input
                    type="text"
                    className="form-control"
                    value={legacyForm.school_year}
                    onChange={(event) => setLegacyForm((current) => ({ ...current, school_year: event.target.value }))}
                    placeholder="2025-2026"
                    required
                  />
                </div>
                <div className="col-md-2">
                  <label className="form-label small">Semester</label>
                  <input
                    type="text"
                    className="form-control"
                    value={legacyForm.semester}
                    onChange={(event) => setLegacyForm((current) => ({ ...current, semester: event.target.value }))}
                    placeholder="Fall / Spring"
                    required
                  />
                </div>
                <div className="col-md-4">
                  <label className="form-label small">Exam type</label>
                  <select
                    className="form-select"
                    value={legacyForm.exam_type}
                    onChange={(event) => setLegacyForm((current) => ({ ...current, exam_type: event.target.value }))}
                  >
                    <option value="">— Select type —</option>
                    {(data?.exam_types ?? []).map((type) => (
                      <option key={type} value={type}>
                        {type}
                      </option>
                    ))}
                  </select>
                </div>
                <div className="col-12">
                  <label className="form-label small">Upload file</label>
                  <input
                    className="form-control"
                    type="file"
                    accept={allowedExtensions.map((ext) => `.${ext}`).join(',')}
                    onChange={(event) => setLegacyFile(event.target.files?.[0] ?? null)}
                    required
                  />
                  <div className="form-text">Allowed: {allowedExtensions.join(', ')} • Max {maxUploadMb} MB</div>
                </div>
                <div className="col-12">
                  <button className="btn btn-primary" type="submit" disabled={!legacyFile}>
                    Upload legacy exam
                  </button>
                </div>
              </form>
            </div>
          </div>

          <div className="card mb-4">
            <div className="card-body">
              {Object.keys(legacyByClass).length === 0 ? (
                <p className="text-muted mb-0">No legacy exams uploaded yet.</p>
              ) : (
                Object.values(legacyByClass).map((group) => (
                  <div className="mb-4" key={group.class_section_id}>
                    <h6 className="mb-2">{group.class_section_name ?? 'Class'}</h6>
                    <div className="list-group">
                      {(group.items ?? []).map((item) => {
                        const finalPath = finalFilePath(item.final_pdf_file ?? item.final_file)
                        return (
                          <div className="list-group-item" key={item.id}>
                            <div className="d-flex flex-column flex-lg-row justify-content-between gap-2">
                              <div>
                                <div className="fw-semibold">{item.draft_title ?? item.exam_type ?? 'Legacy exam'}</div>
                                <div className="small text-muted">
                                  {item.exam_type ?? '—'} • {item.school_year ?? '—'} • {item.semester ?? '—'}
                                </div>
                              </div>
                              <div className="d-flex align-items-center gap-2 flex-wrap">
                                <span className={`badge ${statusBadgeClass(item.status)}`}>{item.status ?? '—'}</span>
                                {finalPath ? (
                                  <button
                                    type="button"
                                    className="btn btn-sm btn-outline-primary"
                                    onClick={() => void openProtectedApiFile(finalPath)}
                                  >
                                    View final
                                  </button>
                                ) : null}
                              </div>
                            </div>
                          </div>
                        )
                      })}
                    </div>
                  </div>
                ))
              )}
            </div>
          </div>
        </>
      )}
    </AdminParityShell>
  )
}

export function AdminGradingManagementPage() {
  const [data, setData] = useState<Awaited<ReturnType<typeof fetchGradingOverview>> | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [activeGradeKey, setActiveGradeKey] = useState<string>('')

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      setLoading(true)
      try {
        const result = await fetchGradingOverview()
        if (cancelled) return
        setData(result)
        setActiveGradeKey(Object.keys(result.grades ?? {})[0] ?? '')
        setError(null)
      } catch (e) {
        if (!cancelled) setError(e instanceof Error ? e.message : 'Unable to load grading management.')
      } finally {
        if (!cancelled) setLoading(false)
      }
    })()
    return () => {
      cancelled = true
    }
  }, [])

  const grades = data?.grades ?? {}
  const studentsBySection = data?.students_by_section ?? {}
  const actionTypes = ['homework', 'quiz', 'project', 'midterm', 'final', 'comments']

  return (
    <AdminParityShell title="Score Management">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      {loading ? (
        <p className="text-muted">Loading grading overview…</p>
      ) : Object.keys(grades).length === 0 ? (
        <p className="text-muted">No grading sections found.</p>
      ) : (
        <>
          <ul className="nav nav-tabs justify-content-center flex-wrap">
            {Object.keys(grades).map((classId) => (
              <li key={classId} className="nav-item">
                <button
                  type="button"
                  className={`nav-link ${classId === activeGradeKey ? 'active' : ''}`}
                  onClick={() => setActiveGradeKey(classId)}
                >
                  {Number(classId) === 12 ? 'Youth' : `Grade ${classId}`}
                </button>
              </li>
            ))}
          </ul>

          <div className="mt-4">
            {(grades[activeGradeKey] ?? []).map((section) => {
              const rows: GradingOverviewStudentRow[] = studentsBySection[String(section.class_section_id)] ?? []
              if (rows.length === 0) return null
              return (
                <div key={section.class_section_id} className="mb-4">
                  <h4 className="text-center mt-4">{section.class_section_name}</h4>
                  <div className="table-responsive">
                    <table className="table table-bordered table-striped align-middle">
                      <thead>
                        <tr>
                          <th>Student Name</th>
                          <th>School ID</th>
                          <th>Actions</th>
                        </tr>
                      </thead>
                      <tbody>
                        {rows.map((student) => (
                          <tr key={student.id}>
                            <td>{`${student.firstname ?? ''} ${student.lastname ?? ''}`.trim()}</td>
                            <td>{student.school_id ?? '—'}</td>
                            <td>
                              {actionTypes.map((type) => (
                                <Link
                                  key={type}
                                  className="btn btn-sm btn-outline-primary m-1"
                                  to={`/app/grading/scores/${type}/${section.class_section_id}/${student.id}`}
                                >
                                  {type.charAt(0).toUpperCase() + type.slice(1)}
                                </Link>
                              ))}
                            </td>
                          </tr>
                        ))}
                      </tbody>
                    </table>
                  </div>
                </div>
              )
            })}
          </div>
        </>
      )}
    </AdminParityShell>
  )
}

export function AdminIpBansPage() {
  const [status, setStatus] = useState<'all' | 'active'>('all')
  const [rows, setRows] = useState<Array<Record<string, unknown>>>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [sortCol, setSortCol] = useState('id')
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('desc')
  const [pageSize, setPageSize] = useState(25)
  const [page, setPage] = useState(1)

  async function load(currentStatus = status) {
    setLoading(true)
    try {
      const data = await fetchIpBans({ status: currentStatus, perPage: 200 })
      setRows((data.data?.bans as Array<Record<string, unknown>>) ?? [])
      setPage(1)
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load IP bans.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => { void load(status) }, [status])

  function handleSort(col: string) {
    if (col === sortCol) {
      setSortDir((d) => (d === 'asc' ? 'desc' : 'asc'))
    } else {
      setSortCol(col)
      setSortDir('asc')
    }
    setPage(1)
  }

  const sortedRows = useMemo(() => {
    const copy = [...rows]
    copy.sort((a, b) => {
      let av: string | number = String(a[sortCol] ?? '')
      let bv: string | number = String(b[sortCol] ?? '')
      if (['id', 'attempts'].includes(sortCol)) {
        av = Number(av)
        bv = Number(bv)
      }
      if (av < bv) return sortDir === 'asc' ? -1 : 1
      if (av > bv) return sortDir === 'asc' ? 1 : -1
      return 0
    })
    return copy
  }, [rows, sortCol, sortDir])

  const totalPages = Math.max(1, Math.ceil(sortedRows.length / pageSize))
  const pagedRows = sortedRows.slice((page - 1) * pageSize, page * pageSize)

  async function onUnban(id?: number, all = false) {
    await unbanIp(all ? { all: true } : { id })
    await load()
  }

  async function onBan(id?: number) {
    await banIp({ id, hours: 24 })
    await load()
  }

  return (
    <AdminParityShell title="IP Bans">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <div className="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
        <div className="d-flex align-items-center gap-2">
          <label>Show</label>
          <select className="form-select form-select-sm" style={{ minWidth: 160 }} value={status} onChange={(e) => { setStatus(e.target.value as 'all' | 'active'); setPage(1) }}>
            <option value="all">All entries</option>
            <option value="active">Active bans only</option>
          </select>
          <label className="ms-2">Per page</label>
          <select className="form-select form-select-sm" style={{ width: 80 }} value={pageSize} onChange={(e) => { setPageSize(Number(e.target.value)); setPage(1) }}>
            {[10, 25, 50, 100].map((n) => <option key={n} value={n}>{n}</option>)}
          </select>
        </div>
        <button className="btn btn-danger btn-sm" type="button" onClick={() => void onUnban(undefined, true)}>
          Unban All
        </button>
      </div>
      <div className="table-responsive">
        <table className="table table-striped table-hover align-middle">
          <thead className="table-dark">
            <tr>
              <SortTh col="id"              label="ID"            sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="ip_address"      label="IP Address"    sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="attempts"        label="Attempts"      sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="last_attempt_at" label="Last Attempt"  sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="blocked_until"   label="Blocked Until" sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="is_active"       label="Status"        sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="created_at"      label="Created"       sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <SortTh col="updated_at"      label="Updated"       sortCol={sortCol} sortDir={sortDir} onSort={handleSort} />
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={9} className="text-muted">Loading IP bans…</td></tr>
            ) : pagedRows.length === 0 ? (
              <tr><td colSpan={9} className="text-muted">No IP ban records found.</td></tr>
            ) : pagedRows.map((row) => {
              const id = Number(row.id ?? 0)
              const active = Boolean(row.is_active)
              return (
                <tr key={id}>
                  <td>{id}</td>
                  <td>{String(row.ip_address ?? '—')}</td>
                  <td>{String(row.attempts ?? 0)}</td>
                  <td>{formatDate(String(row.last_attempt_at ?? ''))}</td>
                  <td>{formatDate(String(row.blocked_until ?? ''))}</td>
                  <td><span className={`badge ${active ? 'bg-danger' : 'bg-secondary'}`}>{active ? 'Active' : 'Not Active'}</span></td>
                  <td>{formatDate(String(row.created_at ?? ''))}</td>
                  <td>{formatDate(String(row.updated_at ?? ''))}</td>
                  <td className="d-flex gap-2">
                    {active ? (
                      <button className="btn btn-sm btn-primary" type="button" onClick={() => void onUnban(id)}>Unban</button>
                    ) : (
                      <>
                        <button className="btn btn-sm btn-warning" type="button" onClick={() => void onBan(id)}>Ban 24h</button>
                        <button className="btn btn-sm btn-secondary" type="button" onClick={() => void onUnban(id)}>Clear Attempts</button>
                      </>
                    )}
                  </td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
      {totalPages > 1 && (
        <div className="d-flex align-items-center justify-content-between mt-2 flex-wrap gap-2">
          <small className="text-muted">
            Showing {Math.min((page - 1) * pageSize + 1, sortedRows.length)}–{Math.min(page * pageSize, sortedRows.length)} of {sortedRows.length}
          </small>
          <nav>
            <ul className="pagination pagination-sm mb-0">
              <li className={`page-item ${page === 1 ? 'disabled' : ''}`}>
                <button className="page-link" onClick={() => setPage(1)}>&laquo;</button>
              </li>
              <li className={`page-item ${page === 1 ? 'disabled' : ''}`}>
                <button className="page-link" onClick={() => setPage((p) => p - 1)}>&lsaquo;</button>
              </li>
              {Array.from({ length: totalPages }, (_, i) => i + 1)
                .filter((p) => p === 1 || p === totalPages || Math.abs(p - page) <= 2)
                .reduce<(number | '…')[]>((acc, p, i, arr) => {
                  if (i > 0 && p - (arr[i - 1] as number) > 1) acc.push('…')
                  acc.push(p)
                  return acc
                }, [])
                .map((p, i) =>
                  p === '…' ? (
                    <li key={`ellipsis-${i}`} className="page-item disabled"><span className="page-link">…</span></li>
                  ) : (
                    <li key={p} className={`page-item ${page === p ? 'active' : ''}`}>
                      <button className="page-link" onClick={() => setPage(p as number)}>{p}</button>
                    </li>
                  )
                )}
              <li className={`page-item ${page === totalPages ? 'disabled' : ''}`}>
                <button className="page-link" onClick={() => setPage((p) => p + 1)}>&rsaquo;</button>
              </li>
              <li className={`page-item ${page === totalPages ? 'disabled' : ''}`}>
                <button className="page-link" onClick={() => setPage(totalPages)}>&raquo;</button>
              </li>
            </ul>
          </nav>
        </div>
      )}
    </AdminParityShell>
  )
}

export function AdminLateSlipLogsPage() {
  const [filters, setFilters] = useState({ schoolYear: '', semester: '', q: '', dateFrom: '', dateTo: '' })
  const [rows, setRows] = useState<Array<Record<string, unknown>>>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  async function load() {
    setLoading(true)
    try {
      const data = await fetchLateSlipLogs({ ...filters, perPage: 100 })
      setRows((data.data?.logs as Array<Record<string, unknown>>) ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load late slip logs.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  return (
    <AdminParityShell title="Late Slip Logs">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <form className="row g-2 align-items-end mb-3" onSubmit={(e) => { e.preventDefault(); void load() }}>
        <div className="col-auto"><label className="form-label">School Year</label><input className="form-control" value={filters.schoolYear} onChange={(e) => setFilters((c) => ({ ...c, schoolYear: e.target.value }))} /></div>
        <div className="col-auto"><label className="form-label">Semester</label><select className="form-select" value={filters.semester} onChange={(e) => setFilters((c) => ({ ...c, semester: e.target.value }))}><option value="">—</option><option value="Fall">Fall</option><option value="Spring">Spring</option></select></div>
        <div className="col-auto"><label className="form-label">Student</label><input className="form-control" value={filters.q} onChange={(e) => setFilters((c) => ({ ...c, q: e.target.value }))} /></div>
        <div className="col-auto"><label className="form-label">From</label><input type="date" className="form-control" value={filters.dateFrom} onChange={(e) => setFilters((c) => ({ ...c, dateFrom: e.target.value }))} /></div>
        <div className="col-auto"><label className="form-label">To</label><input type="date" className="form-control" value={filters.dateTo} onChange={(e) => setFilters((c) => ({ ...c, dateTo: e.target.value }))} /></div>
        <div className="col-auto d-flex gap-2"><button className="btn btn-primary" type="submit">Filter</button><button className="btn btn-secondary" type="button" onClick={() => { setFilters({ schoolYear: '', semester: '', q: '', dateFrom: '', dateTo: '' }); }}>Reset</button></div>
      </form>
      <div className="table-responsive">
        <table className="table table-striped align-middle">
          <thead><tr><th>ID</th><th>Printed At</th><th>Student</th><th>Grade</th><th>Date</th><th>Time In</th><th>Reason</th><th>School Year</th><th>Admin</th><th>Action</th></tr></thead>
          <tbody>
            {loading ? <tr><td colSpan={10} className="text-muted">Loading logs…</td></tr> : rows.length === 0 ? <tr><td colSpan={10} className="text-muted">No late slip logs found.</td></tr> : rows.map((row) => (
              <tr key={String(row.id ?? '')}>
                <td>{String(row.id ?? '')}</td>
                <td>{formatDate(String(row.printed_at ?? ''))}</td>
                <td>{String(row.student_name ?? '—')}</td>
                <td>{String(row.grade ?? '—')}</td>
                <td>{formatDate(String(row.slip_date ?? ''))}</td>
                <td>{String(row.time_in ?? '—')}</td>
                <td>{String(row.reason ?? '—')}</td>
                <td>{String(row.school_year ?? '—')}</td>
                <td>{String(row.admin_name ?? '—')}</td>
                <td><button className="btn btn-sm btn-outline-danger" type="button" onClick={() => void deleteLateSlipLog(Number(row.id)).then(load)}>Delete</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminManageUsersPage() {
  const [rows, setRows] = useState<UserListRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  async function load() {
    setLoading(true)
    try {
      const data = await fetchUsers({ sort: 'lastname', order: 'asc' })
      setRows(data.users ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load users.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => { void load() }, [])

  return (
    <AdminParityShell title="Manage Users">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <div className="table-responsive">
        <table className="table table-bordered mt-3 align-middle">
          <thead><tr><th>ID</th><th>Name</th><th>Email</th><th>Role</th><th>Actions</th></tr></thead>
          <tbody>
            {loading ? <tr><td colSpan={5} className="text-muted">Loading users…</td></tr> : rows.length === 0 ? <tr><td colSpan={5} className="text-muted">No users found.</td></tr> : rows.map((row) => {
              const user = row.user ?? {}
              const id = Number(user.id ?? 0)
              const name = `${String(user.firstname ?? '')} ${String(user.lastname ?? '')}`.trim()
              return (
                <tr key={id}>
                  <td>{id}</td>
                  <td>{name || '—'}</td>
                  <td>{String(user.email ?? '—')}</td>
                  <td>
                    {(row.roles ?? [])
                      .map((role) => {
                        if (typeof role === 'string') return role
                        return String(role.name ?? role.slug ?? '')
                      })
                      .filter(Boolean)
                      .join(', ') || '—'}
                  </td>
                  <td><button className="btn btn-sm btn-danger" type="button" onClick={() => void deleteUser(id).then(load)}>Delete</button></td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

function AdminNotificationMatrix({
  title,
  admins,
  columns,
  checkedMap,
  onSave,
  tableReady,
}: {
  title: string
  admins: NotificationAdminRow[]
  columns: Array<{ key: string; label: string }>
  checkedMap: Record<string, Record<string, boolean>>
  onSave: (value: Record<string, Record<string, boolean>>) => Promise<void>
  tableReady: boolean
}) {
  const [state, setState] = useState(checkedMap)
  useEffect(() => setState(checkedMap), [checkedMap])
  return (
    <AdminParityShell title={title}>
      {!tableReady ? <div className="alert alert-warning">Notification subject storage is not available.</div> : null}
      <div className="card">
        <div className="card-header d-flex justify-content-between"><span>Admins</span><button className="btn btn-primary btn-sm" type="button" disabled={!tableReady} onClick={() => void onSave(state)}>Save</button></div>
        <div className="card-body p-0">
          <div className="table-responsive">
            <table className="table table-striped align-middle mb-0">
              <thead className="table-dark"><tr><th>#</th><th>Name</th><th>Email</th>{columns.map((c) => <th key={c.key} className="text-center">{c.label}</th>)}</tr></thead>
              <tbody>
                {admins.length === 0 ? <tr><td colSpan={3 + columns.length} className="text-center text-muted">No admins found.</td></tr> : admins.map((admin, index) => {
                  const id = String(admin.id)
                  return (
                    <tr key={id}>
                      <td>{index + 1}</td>
                      <td>{`${admin.firstname ?? ''} ${admin.lastname ?? ''}`.trim() || `Admin #${id}`}</td>
                      <td>{admin.email ?? ''}</td>
                      {columns.map((c) => (
                        <td key={c.key} className="text-center">
                          <input className="form-check-input" type="checkbox" checked={Boolean(state[id]?.[c.key])} disabled={!tableReady} onChange={(e) => setState((current) => ({ ...current, [id]: { ...(current[id] ?? {}), [c.key]: e.target.checked } }))} />
                        </td>
                      ))}
                    </tr>
                  )
                })}
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

export function AdminNotificationsAlertsPage() {
  const [admins, setAdmins] = useState<NotificationAdminRow[]>([])
  const [subjects, setSubjects] = useState<Record<string, string>>({})
  const [assigned, setAssigned] = useState<Record<string, Record<string, boolean>>>({})
  const [tableReady, setTableReady] = useState(false)

  useEffect(() => {
    ;(async () => {
      const data = await fetchNotificationAlerts()
      setAdmins(data.admins ?? [])
      setSubjects(data.subjects ?? {})
      setAssigned(data.assignedSubjects ?? {})
      setTableReady(Boolean(data.tableReady))
    })()
  }, [])

  return (
    <AdminNotificationMatrix
      title="Admin Notification Subjects"
      admins={admins}
      columns={Object.entries(subjects).map(([key, label]) => ({ key, label }))}
      checkedMap={assigned}
      tableReady={tableReady}
      onSave={async (value) => {
        const payload: Record<string, string[]> = {}
        for (const [adminId, map] of Object.entries(value)) {
          payload[adminId] = Object.entries(map).filter(([, checked]) => checked).map(([key]) => key)
        }
        await saveNotificationAlerts(payload)
      }}
    />
  )
}

export function AdminPrintNotificationAdminsPage() {
  const [admins, setAdmins] = useState<NotificationAdminRow[]>([])
  const [assigned, setAssigned] = useState<Record<string, boolean>>({})
  const [tableReady, setTableReady] = useState(false)

  useEffect(() => {
    ;(async () => {
      const data = await fetchPrintNotificationRecipients()
      setAdmins(data.admins ?? [])
      setAssigned(data.assigned ?? {})
      setTableReady(Boolean(data.tableReady))
    })()
  }, [])

  return (
    <AdminNotificationMatrix
      title="Print Notification Recipients"
      admins={admins}
      columns={[{ key: 'print_requests', label: 'Send Print Alerts' }]}
      checkedMap={Object.fromEntries(Object.entries(assigned).map(([id, checked]) => [id, { print_requests: checked }]))}
      tableReady={tableReady}
      onSave={async (value) => {
        const payload: Record<string, number> = {}
        for (const [adminId, map] of Object.entries(value)) {
          if (map.print_requests) payload[adminId] = 1
        }
        await savePrintNotificationRecipients(payload)
      }}
    />
  )
}

export function AdminParentProfilePage() {
  const [guardians, setGuardians] = useState<NotificationAdminRow[]>([])
  const [selectedGuardianId, setSelectedGuardianId] = useState<number | null>(null)
  const [families, setFamilies] = useState<Array<Record<string, unknown>>>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    ;(async () => {
      setLoading(true)
      try {
        const data = await fetchFamilyAdminIndex()
        setGuardians(data.data?.searchGuardians ?? [])
        setFamilies((data.data?.families as Array<Record<string, unknown>>) ?? [])
        setError(null)
      } catch (e) {
        setError(e instanceof ApiHttpError ? e.message : e instanceof Error ? e.message : 'Unable to load parent profiles.')
      } finally {
        setLoading(false)
      }
    })()
  }, [])

  async function loadGuardian(guardianId: number) {
    setSelectedGuardianId(guardianId)
    setError(null)
    try {
      const data = await fetchFamilyAdminIndex({ guardianId })
      setFamilies((data.data?.families as Array<Record<string, unknown>>) ?? [])
    } catch (e) {
      setError(e instanceof ApiHttpError ? e.message : e instanceof Error ? e.message : 'Unable to load families.')
    }
  }

  return (
    <AdminParityShell title="Parent Profiles">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <div className="row g-3">
        <div className="col-lg-4">
          <div className="card">
            <div className="card-header">Guardians</div>
            <div className="list-group list-group-flush" style={{ maxHeight: 520, overflow: 'auto' }}>
              {loading ? <div className="list-group-item text-muted">Loading guardians…</div> : guardians.map((guardian) => (
                <button key={guardian.id} type="button" className={`list-group-item list-group-item-action ${selectedGuardianId === guardian.id ? 'active' : ''}`} onClick={() => void loadGuardian(guardian.id)}>
                  <div>{`${guardian.firstname ?? ''} ${guardian.lastname ?? ''}`.trim()}</div>
                  <div className="small">{guardian.email ?? ''}</div>
                </button>
              ))}
            </div>
          </div>
        </div>
        <div className="col-lg-8">
          <div className="card">
            <div className="card-header">Families</div>
            <div className="card-body">
              {families.length === 0 ? <p className="text-muted mb-0">Select a guardian to view family details.</p> : families.map((family) => (
                <div key={String(family.id ?? '')} className="border rounded p-3 mb-3">
                  <h5 className="mb-1">{String(family.household_name ?? 'Household')}</h5>
                  <div className="small text-muted mb-2">{String(family.address_line1 ?? '')} {String(family.city ?? '')} {String(family.state ?? '')}</div>
                  <div className="mb-2"><strong>Phone:</strong> {String(family.primary_phone ?? '—')}</div>
                  <div><strong>Students</strong></div>
                  <ul className="mb-0">
                    {Array.isArray(family.students) && family.students.length > 0 ? family.students.map((student, idx) => (
                      <li key={idx}>{`${String(student.firstname ?? '')} ${String(student.lastname ?? '')}`.trim()} {student.class_section_name ? `(${String(student.class_section_name)})` : ''}</li>
                    )) : <li className="text-muted">No students linked.</li>}
                  </ul>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

export function AdminPaypalTransactionsPage() {
  const [q, setQ] = useState('')
  const [rows, setRows] = useState<Array<Record<string, unknown>>>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  async function load(query = q) {
    setLoading(true)
    try {
      const data = await fetchPaypalTransactions({ q: query || undefined, perPage: 100 })
      setRows((data.transactions as Array<Record<string, unknown>>) ?? [])
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load PayPal transactions.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => { void load('') }, [])

  async function exportCsv() {
    const blob = await fetchPaypalTransactionsCsv({ q: q || undefined })
    const url = URL.createObjectURL(blob)
    const anchor = document.createElement('a')
    anchor.href = url
    anchor.download = 'paypal_transactions.csv'
    anchor.click()
    URL.revokeObjectURL(url)
  }

  return (
    <AdminParityShell title="PayPal Transactions">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <div className="d-flex gap-2 mb-3 justify-content-end">
        <input className="form-control" style={{ maxWidth: 320 }} placeholder="Search transactions" value={q} onChange={(e) => setQ(e.target.value)} />
        <button className="btn btn-primary" type="button" onClick={() => void load()}>Search</button>
        <button className="btn btn-success" type="button" onClick={() => void exportCsv()}>Export CSV</button>
      </div>
      <div className="table-responsive">
        <table className="table table-striped align-middle">
          <thead><tr><th>ID</th><th>Transaction ID</th><th>Order ID</th><th>Parent School ID</th><th>Email</th><th>Amount</th><th>Net Amount</th><th>Currency</th><th>Status</th><th>Event Type</th><th>Date</th></tr></thead>
          <tbody>
            {loading ? <tr><td colSpan={11} className="text-muted">Loading transactions…</td></tr> : rows.length === 0 ? <tr><td colSpan={11} className="text-muted">No transactions found.</td></tr> : rows.map((row) => (
              <tr key={String(row.id ?? '')}>
                <td>{String(row.id ?? '')}</td>
                <td>{String(row.transaction_id ?? '—')}</td>
                <td>{String(row.order_id ?? '—')}</td>
                <td>{String(row.parent_school_id ?? '—')}</td>
                <td>{String(row.payer_email ?? '—')}</td>
                <td>{Number(row.amount ?? 0).toFixed(2)}</td>
                <td>{Number(row.net_amount ?? 0).toFixed(2)}</td>
                <td>{String(row.currency ?? '—')}</td>
                <td>{String(row.status ?? '—')}</td>
                <td>{String(row.event_type ?? '—')}</td>
                <td>{formatDate(String(row.created_at ?? ''))}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

function submissionBadgeClass(status?: {
  label?: string | null
  badge?: string | null
  completed?: boolean
} | null) {
  const badge = String(status?.badge ?? '').trim()
  if (badge !== '') return badge
  if (status?.completed === true) return 'bg-success'
  if (status?.completed === false) return 'bg-danger'
  return 'bg-secondary'
}

function submissionBadgeLabel(status?: {
  label?: string | null
  detail?: string | null
} | null) {
  const label = String(status?.label ?? '').trim() || 'Missing'
  const detail = String(status?.detail ?? '').trim()
  return detail !== '' ? `${label} (${detail})` : label
}

export function AdminRemovedStudentsPage() {
  const [schoolYear, setSchoolYear] = useState('')
  const [activeStudents, setActiveStudents] = useState<RemovedStudentRow[]>([])
  const [removedStudents, setRemovedStudents] = useState<RemovedStudentRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  async function load(year = schoolYear) {
    setLoading(true)
    try {
      const data = await fetchRemovedStudents(year || undefined)
      setActiveStudents(data.active_students ?? [])
      setRemovedStudents(data.removed_students ?? [])
      setSchoolYear(data.school_year ?? year ?? '')
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load removed students.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function toggleStudent(studentId: number, isActive: boolean) {
    await setStudentActive({ student_id: studentId, is_active: isActive })
    await load()
  }

  return (
    <AdminParityShell title="Student Removal">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <CiAcademicFilter
        selectedYear={schoolYear}
        onApply={({ schoolYear: year }) => void load(year)}
      />
      <div className="row g-4">
        <div className="col-xl-6">
          <div className="card shadow-sm">
            <div className="card-header d-flex justify-content-between align-items-center">
              <span>Active Students</span>
              <span className="badge bg-primary">{activeStudents.length}</span>
            </div>
            <div className="table-responsive">
              <table className="table table-striped table-hover align-middle mb-0">
                <thead className="table-dark">
                  <tr><th>School ID</th><th>First Name</th><th>Last Name</th><th>Class</th><th>Action</th></tr>
                </thead>
                <tbody>
                  {loading ? <tr><td colSpan={5} className="text-muted">Loading students…</td></tr> : activeStudents.length === 0 ? <tr><td colSpan={5} className="text-muted">No active students found.</td></tr> : activeStudents.map((student) => (
                    <tr key={student.id}>
                      <td>{student.school_id ?? '—'}</td>
                      <td>{student.firstname ?? '—'}</td>
                      <td>{student.lastname ?? '—'}</td>
                      <td>{student.class_section_name ?? 'No class assigned'}</td>
                      <td><button className="btn btn-outline-danger btn-sm" type="button" onClick={() => void toggleStudent(student.id, false)}>Remove</button></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
        <div className="col-xl-6">
          <div className="card shadow-sm">
            <div className="card-header d-flex justify-content-between align-items-center">
              <span>Removed Students</span>
              <span className="badge bg-secondary">{removedStudents.length}</span>
            </div>
            <div className="table-responsive">
              <table className="table table-striped table-hover align-middle mb-0">
                <thead className="table-dark">
                  <tr><th>School ID</th><th>First Name</th><th>Last Name</th><th>Last Class</th><th>Action</th></tr>
                </thead>
                <tbody>
                  {loading ? <tr><td colSpan={5} className="text-muted">Loading students…</td></tr> : removedStudents.length === 0 ? <tr><td colSpan={5} className="text-muted">No removed students found.</td></tr> : removedStudents.map((student) => (
                    <tr key={student.id}>
                      <td>{student.school_id ?? '—'}</td>
                      <td>{student.firstname ?? '—'}</td>
                      <td>{student.lastname ?? '—'}</td>
                      <td>{student.class_section_name ?? 'No class assigned'}</td>
                      <td><button className="btn btn-outline-success btn-sm" type="button" onClick={() => void toggleStudent(student.id, true)}>Restore</button></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

export function AdminSearchResultsPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const initialQuery = searchParams.get('query') ?? ''
  const [query, setQuery] = useState(initialQuery)
  const [result, setResult] = useState<AdministratorDashboardSearchResponse | null>(null)
  const [loading, setLoading] = useState(Boolean(initialQuery))
  const [error, setError] = useState<string | null>(null)

  async function runSearch(value: string) {
    const trimmed = value.trim()
    if (!trimmed) {
      setResult(null)
      setSearchParams({})
      return
    }
    setLoading(true)
    try {
      const data = await searchAdministratorDashboard(trimmed)
      setResult(data)
      setSearchParams({ query: trimmed })
      setError(null)
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Unable to load search results.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    if (initialQuery) void runSearch(initialQuery)
  }, [])

  const groups = [
    { key: 'users', label: 'Users' },
    { key: 'students', label: 'Students' },
    { key: 'parents', label: 'Parents' },
    { key: 'staff', label: 'Staff' },
    { key: 'emergency_contacts', label: 'Emergency Contacts' },
  ] as const

  return (
    <AdminParityShell title="Search Results">
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <form className="d-flex gap-2 mb-4" onSubmit={(e) => { e.preventDefault(); void runSearch(query) }}>
        <input className="form-control" value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Enter search term" required />
        <button className="btn btn-primary" type="submit">Search</button>
      </form>
      {!result && !loading ? <p className="text-muted mb-0">Enter a search term to view results.</p> : null}
      {loading ? <p className="text-muted">Loading search results…</p> : null}
      {result && groups.map((group) => {
        const rows = result.results?.[group.key] ?? []
        if (!rows || rows.length === 0) return null
        const columns = Array.from(new Set(rows.flatMap((row) => Object.keys(row))))
        return (
          <div key={group.key} className="card shadow-sm mb-4">
            <div className="card-header">{group.label}</div>
            <div className="table-responsive">
              <table className="table table-bordered table-sm align-middle mb-0">
                <thead className="table-light">
                  <tr>{columns.map((column) => <th key={column}>{column.replace(/_/g, ' ')}</th>)}</tr>
                </thead>
                <tbody>
                  {rows.map((row, index) => (
                    <tr key={`${group.key}-${index}`}>
                      {columns.map((column) => <td key={column}>{String(row[column] ?? '—')}</td>)}
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )
      })}
      {result && groups.every((group) => (result.results?.[group.key] ?? []).length === 0) ? (
        <p className="text-muted">No results found.</p>
      ) : null}
    </AdminParityShell>
  )
}

/** Section-level promotion totals — `GET /api/v1/students/promotion-totals` (JWT). */
export function AdminSectionsPromotionTotalsPage() {
  const [searchParams] = useSearchParams()
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [rows, setRows] = useState<StudentPromotionTotalsRow[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  async function load(year = schoolYear) {
    setLoading(true)
    setError(null)
    try {
      const data = await fetchStudentPromotionTotals(year || undefined)
      setRows(data.rows ?? [])
      setSchoolYear(data.year ?? year ?? '')
    } catch (e) {
      setError(e instanceof ApiHttpError ? e.message : 'Unable to load promotion totals.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  return (
    <AdminParityShell title="Section promotion totals">
      <p className="text-muted small mb-3">
        Per-class/section student counts from the promotion pipeline. Pair with{' '}
        <Link to="/app/administrator/sections/auto-distribute">auto-distribute sections</Link> to create
        sections from these totals.
      </p>

      <div className="d-flex flex-wrap align-items-start justify-content-between gap-2 mb-3">
        <CiAcademicFilter
          selectedYear={schoolYear}
          onApply={({ schoolYear: year }) => void load(year)}
        />
        <Link className="btn btn-outline-primary" to={`/app/administrator/sections/auto-distribute${schoolYear ? `?school_year=${encodeURIComponent(schoolYear)}` : ''}`}>
          Auto-distribute sections
        </Link>
      </div>

      {error ? <div className="alert alert-danger">{error}</div> : null}

      <div className="table-responsive">
        <table className="table table-sm table-striped align-middle">
          <thead className="table-light">
            <tr>
              <th>Class / section</th>
              <th className="text-end">Total students</th>
              <th className="text-muted small">class_id</th>
              <th className="text-muted small">class_section_id</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr>
                <td colSpan={4} className="text-muted">
                  Loading…
                </td>
              </tr>
            ) : rows.length === 0 ? (
              <tr>
                <td colSpan={4} className="text-muted">
                  No promotion totals for this school year.
                </td>
              </tr>
            ) : (
              rows.map((row, i) => {
                const key = String(row.class_section_id ?? row.class_id ?? i)
                return (
                  <tr key={key}>
                    <td>{row.class_section_name ?? '—'}</td>
                    <td className="text-end">{Number(row.total ?? 0)}</td>
                    <td className="text-muted small">{row.class_id ?? '—'}</td>
                    <td className="text-muted small">{row.class_section_id ?? '—'}</td>
                  </tr>
                )
              })
            )}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminSectionsAutoDistributePage() {
  const [searchParams] = useSearchParams()
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [studentsPerSection, setStudentsPerSection] = useState(20)
  const [rows, setRows] = useState<StudentPromotionTotalsRow[]>([])
  const [loading, setLoading] = useState(true)
  const [message, setMessage] = useState<string | null>(null)
  const [distribution, setDistribution] = useState<Record<string, string[]>>({})

  async function load(year = schoolYear) {
    setLoading(true)
    try {
      const data = await fetchStudentPromotionTotals(year || undefined)
      setRows(data.rows ?? [])
      setSchoolYear(data.year ?? year ?? '')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function runDistribution(row: StudentPromotionTotalsRow) {
    const response = await autoDistributeStudents({
      class_id: row.class_id ?? undefined,
      class_section_id: row.class_section_id ?? undefined,
      students_per_section: studentsPerSection,
      school_year: schoolYear || undefined,
    })
    const sections = (response.data?.sections ?? []).map((section) => {
      const name = String(section.class_section_name ?? 'Section')
      const total = Number(section.total ?? 0)
      return `${name}: ${total}`
    })
    setDistribution((current) => ({ ...current, [String(row.class_section_id ?? row.class_id ?? '')]: sections }))
    setMessage(response.message ?? 'Distribution completed.')
  }

  async function runAll() {
    for (const row of rows) {
      // eslint-disable-next-line no-await-in-loop
      await runDistribution(row)
    }
  }

  return (
    <AdminParityShell title="Auto-Distribute Students into Sections">
      {message ? <div className="alert alert-info">{message}</div> : null}
      <div className="row g-2 align-items-end mb-3">
        <div className="col-lg-6">
          <CiAcademicFilter
            selectedYear={schoolYear}
            onApply={({ schoolYear: year }) => void load(year)}
          />
        </div>
        <div className="col-sm-4 col-lg-3">
          <label className="form-label">Students per section</label>
          <input type="number" min={1} className="form-control" value={studentsPerSection} onChange={(e) => setStudentsPerSection(Number(e.target.value) || 1)} />
        </div>
        <div className="col-auto"><button className="btn btn-primary" type="button" onClick={() => void runAll()} disabled={rows.length === 0}>Generate All</button></div>
      </div>
      <div className="table-responsive">
        <table className="table table-sm table-striped align-middle">
          <thead className="table-light">
            <tr><th>Class</th><th>Total</th><th>Sections Needed</th><th>Generated Sections</th><th>Actions</th></tr>
          </thead>
          <tbody>
            {loading ? <tr><td colSpan={5} className="text-muted">Loading totals…</td></tr> : rows.length === 0 ? <tr><td colSpan={5} className="text-muted">No section totals found.</td></tr> : rows.map((row) => {
              const total = Number(row.total ?? 0)
              const needed = studentsPerSection > 0 ? Math.ceil(total / studentsPerSection) : 0
              const key = String(row.class_section_id ?? row.class_id ?? '')
              return (
                <tr key={key}>
                  <td>{row.class_section_name ?? '—'}</td>
                  <td>{total}</td>
                  <td>{needed || '—'}</td>
                  <td>{distribution[key]?.join(', ') ?? '—'}</td>
                  <td><button className="btn btn-sm btn-primary" type="button" onClick={() => void runDistribution(row)}>Generate Sections</button></td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminStudentClassAssignmentPage() {
  const [searchParams] = useSearchParams()
  type StudentAssignmentSortKey =
    | 'name'
    | 'age'
    | 'registration_grade'
    | 'new_student'
    | 'assigned_classes'
    | 'registration_date'
    | 'school_year'
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [students, setStudents] = useState<StudentAssignmentRow[]>([])
  const [classes, setClasses] = useState<StudentAssignmentOption[]>([])
  const [selectedStudentId, setSelectedStudentId] = useState<number | null>(null)
  const [selectedClassIds, setSelectedClassIds] = useState<number[]>([])
  const [eventOnly, setEventOnly] = useState(false)
  const [loading, setLoading] = useState(true)
  const [message, setMessage] = useState<string | null>(null)
  const [tableSearch, setTableSearch] = useState('')
  const [sortConfig, setSortConfig] = useState<{
    key: StudentAssignmentSortKey
    direction: 'asc' | 'desc'
  }>({
    key: 'name',
    direction: 'asc',
  })

  async function load(year = schoolYear) {
    setLoading(true)
    try {
      const data = await fetchStudentAssignments(year || undefined)
      setStudents(data.students ?? [])
      setClasses(data.classes ?? [])
      setSchoolYear(data.selectedYear ?? year ?? '')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function submitAssignment() {
    if (!selectedStudentId || selectedClassIds.length === 0) return
    const result = await assignStudentClass({
      student_id: selectedStudentId,
      class_section_id: selectedClassIds,
      is_event_only: eventOnly,
    })
    setMessage(result.message ?? 'Classes assigned successfully.')
    setSelectedStudentId(null)
    setSelectedClassIds([])
    setEventOnly(false)
    await load()
  }

  async function removeAssignment(studentId: number, classSectionId: number) {
    const result = await removeStudentClass({ student_id: studentId, class_section_id: classSectionId })
    setMessage(result.message ?? 'Class removed successfully.')
    await load()
  }

  function startAssign(student: StudentAssignmentRow) {
    setSelectedStudentId(student.student_id)
    setSelectedClassIds(student.class_section_ids ?? [])
    setEventOnly(false)
    window.scrollTo({ top: 0, behavior: 'smooth' })
  }

  function requestSort(key: StudentAssignmentSortKey) {
    setSortConfig((prev) =>
      prev.key === key
        ? { key, direction: prev.direction === 'asc' ? 'desc' : 'asc' }
        : { key, direction: 'asc' },
    )
  }

  function sortArrow(key: StudentAssignmentSortKey) {
    if (sortConfig.key !== key) return '↕'
    return sortConfig.direction === 'asc' ? '↑' : '↓'
  }

  const displayedStudents = useMemo(() => {
    const query = tableSearch.trim().toLowerCase()
    const filtered = students.filter((student) => {
      if (!query) return true
      const haystack = [
        student.name,
        student.registration_grade,
        student.new_student,
        student.school_year,
        student.registration_date,
        ...(student.class_section_names ?? []),
      ]
        .map((value) => String(value ?? '').toLowerCase())
        .join(' ')
      return haystack.includes(query)
    })

    return [...filtered].sort((left, right) => {
      const direction = sortConfig.direction === 'asc' ? 1 : -1
      if (sortConfig.key === 'age') {
        const a = Number(left.age ?? 0)
        const b = Number(right.age ?? 0)
        return (a - b) * direction
      }

      if (sortConfig.key === 'assigned_classes') {
        const a = (left.class_section_names ?? []).join(', ')
        const b = (right.class_section_names ?? []).join(', ')
        return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) * direction
      }

      const a = String(left[sortConfig.key] ?? '')
      const b = String(right[sortConfig.key] ?? '')
      return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) * direction
    })
  }, [students, tableSearch, sortConfig])

  return (
    <AdminParityShell title="Student Class Assignment">
      {message ? <div className="alert alert-info">{message}</div> : null}
      <div className="row g-3 mb-4">
        <div className="col-lg-4">
          <CiAcademicFilter
            selectedYear={schoolYear}
            onApply={({ schoolYear: year }) => void load(year)}
          />
        </div>
        <div className="col-lg-8">
          <div className="card shadow-sm">
            <div className="card-body row g-2 align-items-end">
              <div className="col-md-4">
                <label className="form-label">Student</label>
                <select className="form-select" value={selectedStudentId ?? ''} onChange={(e) => setSelectedStudentId(e.target.value ? Number(e.target.value) : null)}>
                  <option value="">Select student…</option>
                  {students.map((student) => <option key={student.student_id} value={student.student_id}>{student.name}</option>)}
                </select>
              </div>
              <div className="col-md-5">
                <label className="form-label">Class(es)</label>
                <select
                  className="form-select"
                  multiple
                  size={6}
                  value={selectedClassIds.map(String)}
                  onChange={(e) => setSelectedClassIds(Array.from(e.target.selectedOptions).map((option) => Number(option.value)))}
                >
                  {classes.map((classRow) => <option key={classRow.class_section_id} value={classRow.class_section_id}>{classRow.class_section_name}</option>)}
                </select>
              </div>
              <div className="col-md-3">
                <div className="form-check mb-2">
                  <input id="eventOnly" className="form-check-input" type="checkbox" checked={eventOnly} onChange={(e) => setEventOnly(e.target.checked)} />
                  <label className="form-check-label" htmlFor="eventOnly">Event class only</label>
                </div>
                <button className="btn btn-primary w-100" type="button" onClick={() => void submitAssignment()} disabled={!selectedStudentId || selectedClassIds.length === 0}>Assign Class</button>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div className="d-flex justify-content-end mb-3">
        <div className="input-group" style={{ maxWidth: 360 }}>
          <input
            className="form-control"
            value={tableSearch}
            onChange={(event) => setTableSearch(event.target.value)}
            placeholder="Search students or classes"
          />
          <button className="btn btn-outline-secondary" type="button" onClick={() => setTableSearch('')}>
            Clear
          </button>
        </div>
      </div>
      <div className="table-responsive">
        <table className="table table-striped table-hover align-middle">
          <thead className="table-dark">
            <tr>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('name')}>Student Name {sortArrow('name')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('age')}>Age {sortArrow('age')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('registration_grade')}>Registration Grade {sortArrow('registration_grade')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('new_student')}>New Student {sortArrow('new_student')}</th>
              <th>Assign Class</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('assigned_classes')}>Assigned Classes {sortArrow('assigned_classes')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('registration_date')}>Registration Date {sortArrow('registration_date')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('school_year')}>School Year {sortArrow('school_year')}</th>
            </tr>
          </thead>
          <tbody>
            {loading ? <tr><td colSpan={8} className="text-muted">Loading students…</td></tr> : displayedStudents.length === 0 ? <tr><td colSpan={8} className="text-muted">No students found.</td></tr> : displayedStudents.map((student) => (
              <tr key={student.student_id}>
                <td>{student.name}</td>
                <td>{student.age ?? '—'}</td>
                <td>{student.registration_grade ?? '—'}</td>
                <td>{student.new_student ?? '—'}</td>
                <td>
                  <button
                    className="btn btn-primary btn-sm"
                    type="button"
                    onClick={() => startAssign(student)}
                  >
                    Assign Class
                  </button>
                </td>
                <td>
                  {student.class_section_ids && student.class_section_ids.length > 0 ? (
                    <div className="d-flex flex-wrap gap-2">
                      {student.class_section_ids.map((classId, index) => (
                        <span key={`${student.student_id}-${classId}`} className="badge bg-success d-inline-flex align-items-center gap-2">
                          <span>{student.class_section_names?.[index] ?? `Class ${classId}`}</span>
                          <button className="btn-close btn-close-white" style={{ fontSize: 10 }} type="button" aria-label="Remove class" onClick={() => void removeAssignment(student.student_id, classId)} />
                        </span>
                      ))}
                    </div>
                  ) : (
                    <span className="text-muted">No class assigned</span>
                  )}
                </td>
                <td>{formatDate(student.registration_date)}</td>
                <td>{student.school_year ?? '—'}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminStudentProfilesPage() {
  const [searchParams] = useSearchParams()
  type StudentProfileSortKey =
    | 'school_id'
    | 'firstname'
    | 'lastname'
    | 'dob'
    | 'age'
    | 'gender'
    | 'registration_grade'
    | 'is_active'
    | 'photo_consent'
    | 'registration_date'
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [students, setStudents] = useState<StudentDirectoryRow[]>([])
  const [editing, setEditing] = useState<StudentDirectoryRow | null>(null)
  const [parentDetails, setParentDetails] = useState<Record<string, unknown> | null>(null)
  const [emergencyContacts, setEmergencyContacts] = useState<Array<Record<string, unknown>>>([])
  const [message, setMessage] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [tableSearch, setTableSearch] = useState('')
  const [sortConfig, setSortConfig] = useState<{
    key: StudentProfileSortKey
    direction: 'asc' | 'desc'
  }>({
    key: 'lastname',
    direction: 'asc',
  })

  async function load(year = schoolYear) {
    setLoading(true)
    try {
      const data = await fetchStudentDirectory(year || undefined)
      setStudents(data.students ?? [])
      setSchoolYear(data.school_year ?? year ?? '')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function openDetails(student: StudentDirectoryRow) {
    setEditing(student)
    const [parent, contacts] = await Promise.all([
      fetchStudentParent(student.id),
      fetchStudentEmergencyContacts(student.id),
    ])
    setParentDetails(parent.parent ?? null)
    setEmergencyContacts(contacts.rows ?? [])
  }

  async function saveStudent() {
    if (!editing) return
    const result = await updateStudentProfile(editing.id, {
      school_id: editing.school_id ?? '',
      firstname: editing.firstname ?? '',
      lastname: editing.lastname ?? '',
      dob: editing.dob ?? '',
      age: editing.age ?? null,
      gender: editing.gender ?? 'Male',
      registration_grade: editing.registration_grade ?? '',
      photo_consent: Boolean(editing.photo_consent),
      parent_id: editing.parent_id ?? 0,
      registration_date: editing.registration_date ?? null,
      tuition_paid: Boolean(editing.tuition_paid),
      year_of_registration: editing.year_of_registration ?? '',
      school_year: editing.school_year ?? '',
      semester: editing.semester ?? '',
      is_new: Boolean(editing.is_new),
      is_active: Boolean(editing.is_active),
      medical_conditions: editing.medical_conditions ?? '',
      allergies: editing.allergies ?? '',
    })
    setMessage(result.message ?? 'Student updated successfully.')
    setEditing(null)
    await load()
  }

  function requestSort(key: StudentProfileSortKey) {
    setSortConfig((prev) =>
      prev.key === key
        ? { key, direction: prev.direction === 'asc' ? 'desc' : 'asc' }
        : { key, direction: 'asc' },
    )
  }

  function sortArrow(key: StudentProfileSortKey) {
    if (sortConfig.key !== key) return '↕'
    return sortConfig.direction === 'asc' ? '↑' : '↓'
  }

  const displayedStudents = useMemo(() => {
    const query = tableSearch.trim().toLowerCase()
    const filtered = students.filter((student) => {
      if (!query) return true
      const haystack = [
        student.school_id,
        student.firstname,
        student.lastname,
        student.gender,
        student.registration_grade,
        student.dob,
        student.registration_date,
        Boolean(student.is_active) ? 'yes active' : 'no inactive',
        Boolean(student.photo_consent) ? 'yes consent' : 'no consent',
      ]
        .map((value) => String(value ?? '').toLowerCase())
        .join(' ')
      return haystack.includes(query)
    })

    return [...filtered].sort((left, right) => {
      const direction = sortConfig.direction === 'asc' ? 1 : -1
      if (sortConfig.key === 'age') {
        const a = Number(left.age ?? 0)
        const b = Number(right.age ?? 0)
        return (a - b) * direction
      }
      if (sortConfig.key === 'is_active' || sortConfig.key === 'photo_consent') {
        const a = Number(Boolean(left[sortConfig.key]))
        const b = Number(Boolean(right[sortConfig.key]))
        return (a - b) * direction
      }
      const a = String(left[sortConfig.key] ?? '')
      const b = String(right[sortConfig.key] ?? '')
      return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) * direction
    })
  }, [students, tableSearch, sortConfig])

  return (
    <AdminParityShell title="Student Profiles">
      {message ? <div className="alert alert-info">{message}</div> : null}
      <div className="d-flex flex-wrap gap-2 mb-3 justify-content-between">
        <CiAcademicFilter
          selectedYear={schoolYear}
          onApply={({ schoolYear: year }) => void load(year)}
        />
        <div className="input-group" style={{ maxWidth: 360 }}>
          <input
            className="form-control"
            value={tableSearch}
            onChange={(event) => setTableSearch(event.target.value)}
            placeholder="Search students"
          />
          <button className="btn btn-outline-secondary" type="button" onClick={() => setTableSearch('')}>
            Clear
          </button>
        </div>
      </div>
      <div className="table-responsive">
        <table className="table table-striped table-hover align-middle">
          <thead className="table-dark">
            <tr>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('school_id')}>School ID {sortArrow('school_id')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('firstname')}>First Name {sortArrow('firstname')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('lastname')}>Last Name {sortArrow('lastname')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('dob')}>DOB {sortArrow('dob')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('age')}>Age {sortArrow('age')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('gender')}>Gender {sortArrow('gender')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('registration_grade')}>Assigned Grade {sortArrow('registration_grade')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('is_active')}>Active {sortArrow('is_active')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('photo_consent')}>Photo Consent {sortArrow('photo_consent')}</th>
              <th role="button" style={{ cursor: 'pointer' }} onClick={() => requestSort('registration_date')}>Registration Date {sortArrow('registration_date')}</th>
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            {loading ? <tr><td colSpan={11} className="text-muted">Loading students…</td></tr> : displayedStudents.length === 0 ? <tr><td colSpan={11} className="text-muted">No students found.</td></tr> : displayedStudents.map((student) => (
              <tr key={student.id}>
                <td>{student.school_id ?? '—'}</td>
                <td>{student.firstname ?? '—'}</td>
                <td>{student.lastname ?? '—'}</td>
                <td>{formatDate(student.dob)}</td>
                <td>{student.age ?? '—'}</td>
                <td>{student.gender ?? '—'}</td>
                <td>{student.registration_grade ?? '—'}</td>
                <td>{Boolean(student.is_active) ? 'Yes' : 'No'}</td>
                <td>{Boolean(student.photo_consent) ? 'Yes' : 'No'}</td>
                <td>{formatDate(student.registration_date)}</td>
                <td><button className="btn btn-sm btn-primary" type="button" onClick={() => void openDetails(student)}>View / Edit</button></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      {editing ? (
        <div className="modal d-block position-static mt-4" role="dialog" aria-modal="true">
          <div className="modal-dialog modal-xl">
            <div className="modal-content">
              <div className="modal-header">
                <h5 className="modal-title">Edit Student - {`${editing.firstname ?? ''} ${editing.lastname ?? ''}`.trim()}</h5>
                <button className="btn-close" type="button" onClick={() => setEditing(null)} />
              </div>
              <div className="modal-body">
                <div className="row g-3">
                  <div className="col-md-4"><label className="form-label">School ID</label><input className="form-control" value={editing.school_id ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, school_id: e.target.value } : current)} /></div>
                  <div className="col-md-4"><label className="form-label">First Name</label><input className="form-control" value={editing.firstname ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, firstname: e.target.value } : current)} /></div>
                  <div className="col-md-4"><label className="form-label">Last Name</label><input className="form-control" value={editing.lastname ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, lastname: e.target.value } : current)} /></div>
                  <div className="col-md-3"><label className="form-label">DOB</label><input type="date" className="form-control" value={formatDateInput(editing.dob)} onChange={(e) => setEditing((current) => current ? { ...current, dob: e.target.value } : current)} /></div>
                  <div className="col-md-2"><label className="form-label">Age</label><input type="number" className="form-control" value={editing.age ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, age: Number(e.target.value) || null } : current)} /></div>
                  <div className="col-md-3"><label className="form-label">Gender</label><select className="form-select" value={editing.gender ?? 'Male'} onChange={(e) => setEditing((current) => current ? { ...current, gender: e.target.value } : current)}><option value="Male">Male</option><option value="Female">Female</option><option value="Other">Other</option></select></div>
                  <div className="col-md-4"><label className="form-label">Registration Grade</label><input className="form-control" value={editing.registration_grade ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, registration_grade: e.target.value } : current)} /></div>
                  <div className="col-md-6"><label className="form-label">Medical Conditions</label><input className="form-control" value={editing.medical_conditions ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, medical_conditions: e.target.value } : current)} /></div>
                  <div className="col-md-6"><label className="form-label">Allergies</label><input className="form-control" value={editing.allergies ?? ''} onChange={(e) => setEditing((current) => current ? { ...current, allergies: e.target.value } : current)} /></div>
                </div>
                <hr />
                <div className="row g-4">
                  <div className="col-md-6">
                    <h6>Parent Information</h6>
                    {parentDetails ? (
                      <div className="small">
                        <div>{`${String(parentDetails.firstname ?? '')} ${String(parentDetails.lastname ?? '')}`.trim()}</div>
                        <div>{String(parentDetails.email ?? '—')}</div>
                        <div>{String(parentDetails.cellphone ?? '—')}</div>
                      </div>
                    ) : <p className="text-muted small mb-0">No parent record found.</p>}
                  </div>
                  <div className="col-md-6">
                    <h6>Emergency Contacts</h6>
                    {emergencyContacts.length === 0 ? <p className="text-muted small mb-0">No emergency contacts found.</p> : (
                      <ul className="small mb-0">
                        {emergencyContacts.map((contact, index) => <li key={index}>{String(contact.emergency_contact_name ?? contact.name ?? 'Contact')} - {String(contact.cellphone ?? '—')}</li>)}
                      </ul>
                    )}
                  </div>
                </div>
              </div>
              <div className="modal-footer">
                <button className="btn btn-secondary" type="button" onClick={() => setEditing(null)}>Close</button>
                <button className="btn btn-primary" type="button" onClick={() => void saveStudent()}>Save</button>
              </div>
            </div>
          </div>
        </div>
      ) : null}
    </AdminParityShell>
  )
}

export function AdminSubjectCurriculumPage() {
  const [searchParams] = useSearchParams()
  const [classes, setClasses] = useState<Array<{ id: number; class_name: string }>>([])
  const [entries, setEntries] = useState<SubjectCurriculumEntryRow[]>([])
  const [subjects, setSubjects] = useState<Record<string, string>>({})
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [form, setForm] = useState({ class_id: '', subject: 'islamic', unit_number: '', unit_title: '', chapter_name: '' })
  const [editingId, setEditingId] = useState<number | null>(null)
  const [message, setMessage] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [saving, setSaving] = useState(false)

  async function load(year = schoolYear) {
    setLoading(true)
    setError(null)
    try {
      const data = await fetchSubjectCurriculum(year || undefined)
      setClasses(data.classes ?? [])
      setEntries(data.entries ?? [])
      setSubjects(data.subject_labels ?? {})
      setSchoolYear(data.school_year ?? year ?? '')
    } catch (e: unknown) {
      setError(e instanceof ApiHttpError ? e.message : 'Unable to load curriculum.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [])

  async function submitForm(e: FormEvent) {
    e.preventDefault()
    setSaving(true)
    setError(null)
    const payload = {
      class_id: Number(form.class_id),
      subject: form.subject,
      unit_number: form.unit_number ? Number(form.unit_number) : null,
      unit_title: form.unit_title || null,
      chapter_name: form.chapter_name,
      school_year: schoolYear || undefined,
    }
    try {
      if (editingId) {
        await updateSubjectCurriculum(editingId, payload)
        setMessage('Curriculum entry updated.')
      } else {
        await createSubjectCurriculum(payload)
        setMessage('Curriculum entry created.')
      }
      setEditingId(null)
      setForm({ class_id: '', subject: 'islamic', unit_number: '', unit_title: '', chapter_name: '' })
      await load()
    } catch (e: unknown) {
      setMessage(null)
      setError(e instanceof ApiHttpError ? e.message : 'Unable to save curriculum entry.')
    } finally {
      setSaving(false)
    }
  }

  async function removeEntry(id: number) {
    if (!confirm('Delete this curriculum entry?')) return
    setError(null)
    try {
      await deleteSubjectCurriculum(id)
      setMessage('Curriculum entry deleted.')
      await load()
    } catch (e: unknown) {
      setMessage(null)
      setError(e instanceof ApiHttpError ? e.message : 'Unable to delete curriculum entry.')
    }
  }

  return (
    <AdminParityShell title="Subject Curriculum">
      {message ? <div className="alert alert-info">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <CiAcademicFilter
        selectedYear={schoolYear}
        onApply={({ schoolYear: year }) => void load(year)}
      />
      <div className="row g-4">
        <div className="col-lg-5">
          <div className="card shadow-sm">
            <div className="card-header">{editingId ? 'Edit curriculum entry' : 'Add new curriculum entry'}</div>
            <div className="card-body">
              <form onSubmit={(e) => void submitForm(e)}>
                <fieldset disabled={loading || saving} className="border-0 m-0 p-0">
                <div className="mb-3">
                  <label className="form-label">Class</label>
                  <select className="form-select" value={form.class_id} onChange={(e) => setForm((current) => ({ ...current, class_id: e.target.value }))} required>
                    <option value="">Select a class</option>
                    {classes.map((classRow) => <option key={classRow.id} value={classRow.id}>{classRow.class_name}</option>)}
                  </select>
                </div>
                <div className="mb-3">
                  <label className="form-label">Subject</label>
                  <select className="form-select" value={form.subject} onChange={(e) => setForm((current) => ({ ...current, subject: e.target.value }))} required>
                    {Object.entries(subjects).map(([key, label]) => <option key={key} value={key}>{label}</option>)}
                  </select>
                </div>
                <div className="mb-3"><label className="form-label">Unit / Term number</label><input type="number" className="form-control" value={form.unit_number} onChange={(e) => setForm((current) => ({ ...current, unit_number: e.target.value }))} /></div>
                <div className="mb-3"><label className="form-label">Unit title</label><input className="form-control" value={form.unit_title} onChange={(e) => setForm((current) => ({ ...current, unit_title: e.target.value }))} /></div>
                <div className="mb-3"><label className="form-label">Chapter / Surah</label><input className="form-control" value={form.chapter_name} onChange={(e) => setForm((current) => ({ ...current, chapter_name: e.target.value }))} required /></div>
                <div className="d-flex gap-2">
                  <button
                    className="btn btn-primary flex-grow-1"
                    type="submit"
                    disabled={loading || saving}
                  >
                    {saving ? 'Saving…' : editingId ? 'Apply changes' : 'Save curriculum entry'}
                  </button>
                  {editingId ? (
                    <button
                      className="btn btn-outline-secondary"
                      type="button"
                      disabled={loading || saving}
                      onClick={() => {
                        setEditingId(null)
                        setForm({ class_id: '', subject: 'islamic', unit_number: '', unit_title: '', chapter_name: '' })
                      }}
                    >
                      Cancel
                    </button>
                  ) : null}
                </div>
                </fieldset>
              </form>
            </div>
          </div>
        </div>
        <div className="col-lg-7">
          <div className="card shadow-sm">
            <div className="card-header">Current curriculum entries</div>
            <div className="table-responsive">
              <table className="table table-bordered table-hover align-middle mb-0">
                <thead className="table-light"><tr><th>Class</th><th>School Year</th><th>Subject</th><th>Unit</th><th>Unit title</th><th>Chapter / Surah</th><th>Actions</th></tr></thead>
                <tbody>
                  {loading ? (
                    <tr>
                      <td colSpan={7} className="text-muted">
                        Loading…
                      </td>
                    </tr>
                  ) : entries.length === 0 ? (
                    <tr>
                      <td colSpan={7} className="text-muted">
                        No curriculum records yet.
                      </td>
                    </tr>
                  ) : (
                    entries.map((entry) => (
                      <tr key={entry.id}>
                        <td>{entry.class_name ?? '—'}</td>
                        <td>{entry.school_year ?? schoolYear ?? '—'}</td>
                        <td>{subjects[entry.subject] ?? entry.subject}</td>
                        <td>{entry.unit_number ?? '—'}</td>
                        <td>{entry.unit_title ?? '—'}</td>
                        <td>{entry.chapter_name}</td>
                        <td className="d-flex gap-2">
                          <button
                            className="btn btn-sm btn-outline-primary"
                            type="button"
                            disabled={saving}
                            onClick={() => {
                              setEditingId(entry.id)
                              setForm({
                                class_id: String(entry.class_id),
                                subject: entry.subject,
                                unit_number: entry.unit_number ? String(entry.unit_number) : '',
                                unit_title: entry.unit_title ?? '',
                                chapter_name: entry.chapter_name,
                              })
                            }}
                          >
                            Edit
                          </button>
                          <button
                            className="btn btn-sm btn-outline-danger"
                            type="button"
                            disabled={saving}
                            onClick={() => void removeEntry(entry.id)}
                          >
                            Delete
                          </button>
                        </td>
                      </tr>
                    ))
                  )}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

export function AdminTeacherClassAssignmentPage() {
  const [searchParams] = useSearchParams()
  const [schoolYear, setSchoolYear] = useState(searchParams.get('school_year') ?? '')
  const [teachers, setTeachers] = useState<TeacherClassAssignmentRow[]>([])
  const [classes, setClasses] = useState<TeacherClassOption[]>([])
  const [selectedTeacherId, setSelectedTeacherId] = useState<number | null>(null)
  const [selectedClassId, setSelectedClassId] = useState<number | null>(null)
  const [selectedRole, setSelectedRole] = useState('')
  const [message, setMessage] = useState<string | null>(null)

  async function load(year = schoolYear) {
    const data = await fetchTeacherClassAssignments(year || undefined)
    setTeachers(data.teachers ?? [])
    setClasses(data.classes ?? [])
    setSchoolYear(data.school_year ?? year ?? '')
  }

  useEffect(() => {
    void load()
  }, [])

  async function submitAssignment() {
    if (!selectedTeacherId || !selectedClassId) return
    const teacher = teachers.find((row) => row.teacher_id === selectedTeacherId)
      const result = await assignTeacherClass({
      teacher_id: selectedTeacherId,
      class_section_id: selectedClassId,
      teacher_role: selectedRole || (teacher?.role ?? undefined),
      school_year: schoolYear || undefined,
    })
    setMessage(result.message ?? 'Class assigned successfully.')
    setSelectedTeacherId(null)
    setSelectedClassId(null)
    setSelectedRole('')
    await load()
  }

  async function removeAssignment(teacherId: number, classSectionId: number, position: 'main' | 'ta') {
    const result = await deleteTeacherClassAssignment({
      teacher_id: teacherId,
      class_section_id: classSectionId,
      position,
      school_year: schoolYear || undefined,
    })
    setMessage(result.message ?? 'Assignment removed.')
    await load()
  }

  return (
    <AdminParityShell title="Teacher Class Assignments">
      {message ? <div className="alert alert-info">{message}</div> : null}
      <div className="row g-3 mb-4">
        <div className="col-lg-3"><CiAcademicFilter selectedYear={schoolYear} onApply={({ schoolYear: year }) => void load(year)} /></div>
        <div className="col-lg-3"><label className="form-label">Teacher</label><select className="form-select" value={selectedTeacherId ?? ''} onChange={(e) => { const id = e.target.value ? Number(e.target.value) : null; setSelectedTeacherId(id); const teacher = teachers.find((row) => row.teacher_id === id); setSelectedRole(String(teacher?.role ?? '')) }}><option value="">Select teacher…</option>{teachers.map((teacher) => <option key={teacher.teacher_id} value={teacher.teacher_id}>{teacher.name ?? `${teacher.firstname ?? ''} ${teacher.lastname ?? ''}`.trim()}</option>)}</select></div>
        <div className="col-lg-4"><label className="form-label">Class</label><select className="form-select" value={selectedClassId ?? ''} onChange={(e) => setSelectedClassId(e.target.value ? Number(e.target.value) : null)}><option value="">Select class…</option>{classes.map((classRow) => <option key={classRow.class_section_id} value={classRow.class_section_id}>{classRow.class_section_name}</option>)}</select></div>
        <div className="col-lg-2 d-grid"><button className="btn btn-primary align-self-end" type="button" onClick={() => void submitAssignment()} disabled={!selectedTeacherId || !selectedClassId}>Assign Class</button></div>
      </div>
      <div className="table-responsive">
        <table className="table table-striped table-hover align-middle">
          <thead className="table-dark"><tr><th>#</th><th>First Name</th><th>Last Name</th><th>Email</th><th>Phone</th><th>Role</th><th>Assigned Classes</th><th>School Year</th></tr></thead>
          <tbody>
            {teachers.length === 0 ? <tr><td colSpan={8} className="text-muted">No teachers found.</td></tr> : teachers.map((teacher, index) => (
              <tr key={teacher.teacher_id}>
                <td>{index + 1}</td>
                <td>{teacher.firstname ?? '—'}</td>
                <td>{teacher.lastname ?? '—'}</td>
                <td>{teacher.email ?? '—'}</td>
                <td>{teacher.cellphone ?? '—'}</td>
                <td>{teacher.role ? teacher.role.replace(/_/g, ' ') : '—'}</td>
                <td>
                  {[...(teacher.main_assignments ?? []), ...(teacher.ta_assignments ?? [])].length === 0 ? <span className="text-muted">No classes assigned</span> : (
                    <ul className="list-unstyled mb-0">
                      {(teacher.main_assignments ?? []).map((assignment) => (
                        <li key={`main-${teacher.teacher_id}-${assignment.section_id}`} className="mb-1 d-flex align-items-center justify-content-between gap-2">
                          <span><strong>{assignment.class_section_name ?? 'Class'}</strong> (Main)</span>
                          <button className="btn btn-outline-danger btn-sm" type="button" onClick={() => void removeAssignment(teacher.teacher_id, Number(assignment.section_id), 'main')}>Remove</button>
                        </li>
                      ))}
                      {(teacher.ta_assignments ?? []).map((assignment) => (
                        <li key={`ta-${teacher.teacher_id}-${assignment.section_id}`} className="mb-1 d-flex align-items-center justify-content-between gap-2">
                          <span><strong>{assignment.class_section_name ?? 'Class'}</strong> (TA)</span>
                          <button className="btn btn-outline-danger btn-sm" type="button" onClick={() => void removeAssignment(teacher.teacher_id, Number(assignment.section_id), 'ta')}>Remove</button>
                        </li>
                      ))}
                    </ul>
                  )}
                </td>
                <td>{teacher.school_year ?? schoolYear ?? '—'}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminTeacherSubmissionsPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const [rows, setRows] = useState<TeacherSubmissionReportRow[]>([])
  const [summary, setSummary] = useState<{ total_items?: number; missing_items?: number; submitted_items?: number; submission_percentage?: number }>({})
  const [selected, setSelected] = useState<Record<string, boolean>>({})
  const [message, setMessage] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)
  const [semester, setSemester] = useState<string | null>(null)
  const [schoolYear, setSchoolYear] = useState<string | null>(null)

  async function load() {
    setLoading(true)
    setError(null)
    try {
      const data = await fetchTeacherSubmissions(searchParams)
      setRows(data.rows ?? [])
      setSummary(data.summary ?? {})
      setSemester(data.semester ?? null)
      setSchoolYear(data.schoolYear ?? null)
    } catch (e: unknown) {
      setError(e instanceof ApiHttpError ? e.message : 'Unable to load teacher submissions.')
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    void load()
  }, [searchParams])

  async function sendNotifications() {
    const notify = Object.entries(selected).filter(([, checked]) => checked).map(([id]) => Number(id))
    if (notify.length === 0) return
    const missingItems = Object.fromEntries(
      rows.flatMap((row) =>
        (row.teachers ?? []).map((teacher) => [String(teacher.id), row.missing_items ?? []]),
      ),
    )
    try {
      const result = await notifyTeacherSubmissions({ notify, missing_items: missingItems })
      setMessage(result.message ?? 'Notifications sent.')
      setError(null)
    } catch (e: unknown) {
      setMessage(null)
      setError(e instanceof ApiHttpError ? e.message : 'Unable to send notifications.')
    }
  }

  return (
    <AdminParityShell title="Teacher Submission Dashboard">
      {message ? <div className="alert alert-info">{message}</div> : null}
      {error ? <div className="alert alert-danger">{error}</div> : null}
      <CiAcademicFilter
        selectedYear={searchParams.get('school_year') ?? schoolYear}
        selectedSemester={searchParams.get('semester') ?? semester}
        onApply={({ schoolYear: year, semester: sem }) => {
          const next = new URLSearchParams(searchParams)
          if (year) next.set('school_year', year)
          else next.delete('school_year')
          if (sem) next.set('semester', sem)
          else next.delete('semester')
          setSearchParams(next)
        }}
      />
      <div className="row g-3 mb-4">
        <div className="col-sm-6 col-xl-3"><div className="card shadow-sm"><div className="card-body"><div className="text-uppercase small text-muted">Completion</div><div className="fs-3 fw-semibold">{summary.submission_percentage ?? 0}%</div></div></div></div>
        <div className="col-sm-6 col-xl-3"><div className="card shadow-sm"><div className="card-body"><div className="text-uppercase small text-muted">Missing Items</div><div className="fs-3 fw-semibold">{summary.missing_items ?? 0}</div></div></div></div>
        <div className="col-sm-6 col-xl-3"><div className="card shadow-sm"><div className="card-body"><div className="text-uppercase small text-muted">Submitted</div><div className="fs-3 fw-semibold">{summary.submitted_items ?? 0}</div></div></div></div>
        <div className="col-sm-6 col-xl-3"><div className="card shadow-sm"><div className="card-body"><div className="text-uppercase small text-muted">Term</div><div className="fs-6 fw-semibold">{`${semester ?? '—'} ${schoolYear ?? ''}`.trim()}</div></div></div></div>
      </div>
      <div className="d-flex justify-content-end mb-3">
        <button
          className="btn btn-primary"
          type="button"
          disabled={loading}
          onClick={() => void sendNotifications()}
        >
          Notify Selected Teachers
        </button>
      </div>
      <div className="table-responsive">
        {loading ? <p className="text-muted">Loading…</p> : null}
        <table className="table table-striped table-bordered align-middle">
          <thead className="table-light">
            <tr><th>Notify</th><th>Class-Section</th><th>Teachers</th><th>Midterm Score</th><th>Midterm Comment</th><th>Participation</th><th>PTAP Comment</th><th>Attendance</th><th>Missing Items</th><th>Student Count</th></tr>
          </thead>
          <tbody>
            {!loading && rows.length === 0 ? (
              <tr>
                <td colSpan={10} className="text-muted">
                  No teacher-class assignments found for this term.
                </td>
              </tr>
            ) : null}
            {!loading
              ? rows.map((row) => (
              <tr key={String(row.class_section_id ?? row.class_section ?? '')}>
                <td>
                  <div className="d-flex flex-column gap-1">
                    {(row.teachers ?? []).map((teacher) => (
                      <label key={teacher.id} className="form-check mb-0">
                        <input className="form-check-input" type="checkbox" checked={Boolean(selected[String(teacher.id)])} onChange={(e) => setSelected((current) => ({ ...current, [String(teacher.id)]: e.target.checked }))} />
                        <span className="form-check-label ms-2">{teacher.label}</span>
                      </label>
                    ))}
                  </div>
                </td>
                <td>{row.class_section ?? '—'}</td>
                <td>{(row.teachers ?? []).map((teacher) => teacher.label).join(', ') || '—'}</td>
                <td><span className={`badge ${submissionBadgeClass(row.midterm_score_status)}`}>{submissionBadgeLabel(row.midterm_score_status)}</span></td>
                <td><span className={`badge ${submissionBadgeClass(row.midterm_comment_status)}`}>{submissionBadgeLabel(row.midterm_comment_status)}</span></td>
                <td><span className={`badge ${submissionBadgeClass(row.participation_status)}`}>{submissionBadgeLabel(row.participation_status)}</span></td>
                <td><span className={`badge ${submissionBadgeClass(row.ptap_comment_status)}`}>{submissionBadgeLabel(row.ptap_comment_status)}</span></td>
                <td><span className={`badge ${submissionBadgeClass(row.attendance_status)}`}>{submissionBadgeLabel(row.attendance_status)}</span></td>
                <td>{(row.missing_items ?? []).join(', ') || '—'}</td>
                <td>{row.student_count ?? 0}</td>
              </tr>
            ))
              : null}
          </tbody>
        </table>
      </div>
    </AdminParityShell>
  )
}

export function AdminClassWarningModalPage() {
  const [searchParams] = useSearchParams()
  const warningMessage = searchParams.get('message') ?? 'An unexpected class assignment issue occurred.'

  return (
    <AdminParityShell title="Warning">
      <div className="modal d-block position-static" role="alertdialog" aria-modal="true">
        <div className="modal-dialog modal-dialog-centered">
          <div className="modal-content border-warning">
            <div className="modal-header bg-warning text-dark">
              <h5 className="modal-title">
                <i className="bi bi-exclamation-triangle-fill me-2" aria-hidden />Warning
              </h5>
            </div>
            <div className="modal-body text-dark fs-6">{warningMessage}</div>
            <div className="modal-footer justify-content-between">
              <Link to="/app/administrator/class_assignment" className="btn btn-secondary">
                Back to Class Assignment
              </Link>
            </div>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}

export function AdminCourseMaterialsPage() {
  return (
    <AdminParityShell title="Course Materials">
      <div className="alert alert-secondary">
        The legacy `course_materials.php` view only contained hardcoded sample rows, and there is no
        matching course-materials API in the current backend.
      </div>
      <div className="card">
        <div className="card-body">
          <p className="mb-3">
            I converted this page into an explicit admin placeholder instead of wiring a fake upload
            form with no backend. The current API-backed alternatives in this app are class progress,
            assignments, and class sections.
          </p>
          <div className="d-flex gap-2 flex-wrap">
            <Link className="btn btn-outline-primary" to="/app/administrator/class_assignment">
              Class Assignment
            </Link>
            <Link className="btn btn-outline-primary" to="/app/administrator/class_section">
              Class Sections
            </Link>
            <Link className="btn btn-outline-primary" to="/app/administrator/events">
              Calendar Events
            </Link>
          </div>
        </div>
      </div>
    </AdminParityShell>
  )
}
