"use client";

import { Fragment, useMemo, useRef, useState } from "react";
import { useLang } from "@/context/LanguageContext";
import {
  Alert,
  Button,
  Card,
  EmptyState,
  Input,
  Modal,
  PageHeader,
  PageLoader,
  Pagination,
  Select,
  Spinner,
  StatusBadge,
  Textarea,
  DatePicker,
  usePagination,
} from "@/components/ui";
import { api, useApi } from "@/lib/client";
import { fileToResizedDataUrl, formatBDT, formatDate, formatTime } from "@/lib/utils";
import { ATTENDANCE_STATUSES } from "@/lib/constants";
import { IconDownload } from "@/components/icons";
import {
  IconCamera,
  IconCheck,
  IconEdit,
  IconLayers,
  IconPlus,
  IconTrash,
  IconUsers,
  IconX,
} from "@/components/icons";
import { CredentialsPanel, type PersonOption } from "@/components/CredentialsPanel";
import { emsConfirm } from "@/components/ConfirmDialog";

interface Student {
  id: number;
  roll: string;
  registrationNo: string | null;
  cardNo: string | null;
  cardValidTill: string | null;
  bloodGroup: string | null;
  name: string;
  nameBn: string | null;
  gender: string;
  dob: string | null;
  guardianName: string;
  guardianNameBn: string | null;
  guardianPhone: string;
  motherName: string | null;
  motherNameBn: string | null;
  address: string | null;
  photoUrl: string | null;
  status: string;
  createdAt: string;
  classItemId: number | null;
  className: string | null;
  classNameBn: string | null;
  groupItemId: number | null;
  groupName?: string | null;
  groupNameBn?: string | null;
  departmentItemId: number | null;
  departmentName?: string | null;
  departmentNameBn?: string | null;
  sectionItemId: number | null;
  sectionName: string | null;
  sectionNameBn: string | null;
  shiftItemId: number | null;
  shiftName?: string | null;
  shiftNameBn?: string | null;
  optionalSubjects: { id: number; name: string; nameBn: string }[];
  feesAssigned: number;
  feesPaid: number;
  feesDue: number;
}

interface Report {
  student: Student & { admittedOn: string };
  schedules: {
    id: number;
    title: string;
    headName: string;
    headNameBn: string | null;
    type: string;
    amount: number;
    paid: number;
    due: number;
    status: string;
    dueDate: string;
    month: string | null;
  }[];
  totals: { assigned: number; paid: number; due: number };
}

type Tab = "list" | "attendance" | "activities" | "credentials";

interface AttEntry {
  studentId: number;
  roll: string;
  name: string;
  nameBn: string | null;
  photoUrl: string | null;
  classItemId: number | null;
  className: string | null;
  classNameBn: string | null;
  status: string | null;
  note: string | null;
  inTime?: string | null;
  outTime?: string | null;
  source?: string | null;
}

interface AttSheet {
  date: string;
  subjectItemId: number | null;
  entries: AttEntry[];
  counts: { marked: number; present: number; absent: number; leave: number };
}

interface Activity {
  id: number;
  title: string;
  description: string | null;
  activityDate: string;
  isForAll: boolean;
  recipientCount: number | null;
  createdByName: string | null;
  createdAt: string;
  recipients: { roll: string; name: string }[];
}

interface AcademicItem {
  id: number;
  category: string;
  name: string;
  nameBn: string;
}

function todayISO(): string {
  return new Date().toISOString().slice(0, 10);
}

/** Student photo (data URL) with initials fallback; optionally clickable to change. */
function StudentAvatar({
  name,
  photoUrl,
  size = 36,
  onClick,
  editable,
  title,
}: {
  name: string;
  photoUrl?: string | null;
  size?: number;
  onClick?: () => void;
  editable?: boolean;
  title?: string;
}) {
  return (
    <span
      className={`ems-avatar${onClick ? " ems-avatar-click" : ""}`}
      style={{ width: size, height: size, fontSize: Math.max(10, Math.round(size * 0.36)) }}
      onClick={onClick}
      role={onClick ? "button" : undefined}
      title={title}
    >
      {photoUrl ? <img src={photoUrl} alt={name} loading="lazy" /> : name.slice(0, 2).toUpperCase()}
      {editable && (
        <span className="ems-avatar-edit-badge">
          <IconCamera className="svg-16" />
        </span>
      )}
    </span>
  );
}

/** Read an image file and downscale it (max 256px, JPEG) into a small data URL. */
function studentPhotoFromFile(file: File, max = 256): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = () => reject(new Error("read"));
    reader.onload = () => {
      const url = String(reader.result);
      const img = new Image();
      img.onload = () => {
        const scale = Math.min(1, max / Math.max(img.width, img.height));
        const w = Math.max(1, Math.round(img.width * scale));
        const h = Math.max(1, Math.round(img.height * scale));
        const canvas = document.createElement("canvas");
        canvas.width = w;
        canvas.height = h;
        const ctx = canvas.getContext("2d");
        if (!ctx) return resolve(url);
        // Flatten transparency (PNG) onto white before JPEG encoding
        ctx.fillStyle = "#ffffff";
        ctx.fillRect(0, 0, w, h);
        ctx.drawImage(img, 0, 0, w, h);
        const resized = canvas.toDataURL("image/jpeg", 0.85);
        resolve(resized.length < url.length ? resized : url);
      };
      img.onerror = () => reject(new Error("decode"));
      img.src = url;
    };
    reader.readAsDataURL(file);
  });
}

export default function PortalStudentsPage() {
  const { t, locale } = useLang();
  const { data, loading, reload } = useApi<{ students: Student[] }>("/api/portal/students");
  const [search, setSearch] = useState("");
  const [reportId, setReportId] = useState<number | null>(null);
  const { data: report, loading: reportLoading, reload: reportReload } = useApi<Report>(
    reportId ? `/api/portal/students/${reportId}` : null
  );

  // ---- Student Profile Update System ----
  const { data: poolData, reload: poolReload } = useApi<{
    classes: { id: number; name: string; nameBn: string }[];
    subjects: { id: number; name: string; nameBn: string }[];
    byClass: Record<number, { id: number; name: string; nameBn: string }[]>;
  }>("/api/portal/optional-subjects");
  // upload policy from the central credential
  const { data: uploadPolicy } = useApi<{ imageMaxKb: number; imageMaxDim: number; docMaxKb: number }>(
    "/api/portal/upload-policy"
  );
  const [profileEditor, setProfileEditor] = useState<Student | null>(null);
  const [profileForm, setProfileForm] = useState({
    name: "", nameBn: "", gender: "MALE", dob: "", guardianName: "",
    guardianNameBn: "", guardianPhone: "", motherName: "", motherNameBn: "",
    address: "", photoUrl: "", groupId: "", departmentId: "",
  });
  const [pickedSubjects, setPickedSubjects] = useState<number[]>([]);
  const [profileSaving, setProfileSaving] = useState(false);
  // documents & media (per-student identity scans)
  const [mediaMap, setMediaMap] = useState<Record<string, string>>({});
  const [mediaViewer, setMediaViewer] = useState<{ key: string; dataUrl: string } | null>(null);
  const [mediaBusy, setMediaBusy] = useState<string | null>(null);

  function openProfileEditor(s: Student) {
    setProfileEditor(s);
    setMediaMap({});
    fetch(`/api/portal/students/${s.id}/media`)
      .then((r) => (r.ok ? r.json() : { media: [] }))
      .then((d: { media?: { kind: string; side: string; dataUrl: string }[] }) => {
        const map: Record<string, string> = {};
        for (const m of d.media ?? []) map[`${m.kind}_${m.side}`] = m.dataUrl;
        setMediaMap(map);
      })
      .catch(() => undefined);
    setProfileForm({
      name: s.name,
      nameBn: s.nameBn ?? "",
      gender: s.gender,
      dob: s.dob ? s.dob.slice(0, 10) : "",
      guardianName: s.guardianName,
      guardianNameBn: s.guardianNameBn ?? "",
      guardianPhone: s.guardianPhone,
      motherName: s.motherName ?? "",
      motherNameBn: s.motherNameBn ?? "",
      address: s.address ?? "",
      photoUrl: s.photoUrl ?? "",
      groupId: s.groupItemId ? String(s.groupItemId) : "",
      departmentId: s.departmentItemId ? String(s.departmentItemId) : "",
    });
    setPickedSubjects((s.optionalSubjects ?? []).map((o) => o.id));
  }

  function onPhotoPick(e: React.ChangeEvent<HTMLInputElement>) {
    const file = e.target.files?.[0];
    if (!file) return;
    fileToResizedDataUrl(file)
      .then((dataUrl) => setProfileForm((f) => ({ ...f, photoUrl: dataUrl })))
      .catch(() => setMessage({ type: "error", text: t.portal.studentsPage.photoInvalid }));
  }

  async function uploadMedia(key: string, file: File) {
    if (!profileEditor) return;
    setMediaBusy(key);
    try {
      const dataUrl = await fileToResizedDataUrl(file, uploadPolicy?.imageMaxDim ?? 1024);
      // key = "<KIND>_<SIDE>" where KIND itself contains an underscore
      const parts = key.split("_");
      const side = parts.pop() ?? "";
      const kind = parts.join("_");
      await api(`/api/portal/students/${profileEditor.id}/media`, {
        method: "PUT",
        body: JSON.stringify({ kind, side, dataUrl }),
      });
      setMediaMap((m) => ({ ...m, [key]: dataUrl }));
      setMessage({ type: "success", text: t.portal.studentsPage.mediaSaved });
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setMediaBusy(null);
    }
  }

  async function removeMedia(key: string) {
    if (!profileEditor) return;
    setMediaBusy(key);
    try {
      const dataUrl = mediaMap[key];
      // find id via the list endpoint
      const list = await fetch(`/api/portal/students/${profileEditor.id}/media`).then((r) => r.json());
      const item = (list.media ?? []).find(
        (m: { kind: string; side: string }) => `${m.kind}_${m.side}` === key
      );
      if (item) {
        await api(`/api/portal/students/${profileEditor.id}/media?mediaId=${item.id}`, {
          method: "DELETE",
        });
      }
      setMediaMap((m) => {
        const next = { ...m };
        delete next[key];
        return next;
      });
      setMessage({ type: "success", text: t.portal.studentsPage.mediaRemoved });
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setMediaBusy(null);
    }
  }

  async function saveProfile(e: React.FormEvent) {
    e.preventDefault();
    if (!profileEditor) return;
    setProfileSaving(true);
    setMessage(null);
    try {
      await api(`/api/portal/students/${profileEditor.id}`, {
        method: "PATCH",
        body: JSON.stringify({
          ...profileForm,
          dob: profileForm.dob || null,
          groupItemId: profileForm.groupId ? Number(profileForm.groupId) : null,
          departmentItemId: profileForm.departmentId ? Number(profileForm.departmentId) : null,
          optionalSubjectIds: pickedSubjects,
        }),
      });
      setMessage({ type: "success", text: t.portal.studentsPage.profileUpdated });
      setProfileEditor(null);
      reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setProfileSaving(false);
    }
  }


  // tabs + student attendance
  const [tab, setTab] = useState<Tab>("list");
  const [attMode, setAttMode] = useState<"individual" | "bulk">("individual");
  const [attDate, setAttDate] = useState(todayISO());
  const [attClassId, setAttClassId] = useState("");
  const [attSectionId, setAttSectionId] = useState("");
  const [attShiftId, setAttShiftId] = useState("");
  const [attSubjectId, setAttSubjectId] = useState("");
  const [attDraft, setAttDraft] = useState<Record<number, string>>({});
  const [bulkPicked, setBulkPicked] = useState<Set<number>>(new Set());
  const [attSaving, setAttSaving] = useState(false);
  const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null);

  // student profile photo modal
  const [photoStudent, setPhotoStudent] = useState<Pick<Student, "id" | "name" | "photoUrl"> | null>(null);
  const [photoPreview, setPhotoPreview] = useState<string | null>(null);
  const [photoSaving, setPhotoSaving] = useState(false);
  const photoInputRef = useRef<HTMLInputElement>(null);

  function resetAttEdits() {
    setAttDraft({});
    setBulkPicked(new Set());
  }

  function toggleBulkPick(id: number) {
    setBulkPicked((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }

  function applyBulkStatus(status: string) {
    if (bulkPicked.size === 0) return;
    const next = { ...attDraft };
    bulkPicked.forEach((id) => {
      next[id] = status;
    });
    setAttDraft(next);
  }

  const sheetQuery = `/api/portal/students/attendance?date=${attDate}` +
    (attClassId ? `&classItemId=${attClassId}` : "") +
    (attSectionId ? `&sectionItemId=${attSectionId}` : "") +
    (attShiftId ? `&shiftItemId=${attShiftId}` : "") +
    (attSubjectId ? `&subjectItemId=${attSubjectId}` : "");
  const sheet = useApi<AttSheet>(sheetQuery);
  const academic = useApi<{ items: AcademicItem[] }>("/api/portal/academic");
  const classItems = (academic.data?.items ?? []).filter((i) => i.category === "CLASS");
  const sectionItems = (academic.data?.items ?? []).filter((i) => i.category === "SECTION");
  const shiftItems = (academic.data?.items ?? []).filter((i) => i.category === "SHIFT");
  const subjectItems = (academic.data?.items ?? []).filter((i) => i.category === "SUBJECT");
  const groupItems = (academic.data?.items ?? []).filter((i) => i.category === "GROUP");
  const departmentItems = (academic.data?.items ?? []).filter((i) => i.category === "DEPARTMENT");

  // activities
  const activities = useApi<{ activities: Activity[] }>("/api/portal/activities");
  const activitiesPager = usePagination(activities.data?.activities ?? [], 10);
  const [actOpen, setActOpen] = useState(false);
  const [actForm, setActForm] = useState({ title: "", description: "", date: todayISO(), target: "ALL" as "ALL" | "SELECTED" });
  const [actPicked, setActPicked] = useState<Set<number>>(new Set());
  const [actSaving, setActSaving] = useState(false);

  function togglePicked(id: number) {
    setActPicked((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }

  async function submitActivity(e: React.FormEvent) {
    e.preventDefault();
    setActSaving(true);
    try {
      await api("/api/portal/activities", {
        method: "POST",
        body: JSON.stringify({
          title: actForm.title,
          description: actForm.description,
          activityDate: actForm.date,
          isForAll: actForm.target === "ALL",
          studentIds: actForm.target === "SELECTED" ? Array.from(actPicked) : [],
        }),
      });
      setActOpen(false);
      setActForm({ title: "", description: "", date: todayISO(), target: "ALL" });
      setActPicked(new Set());
      setMessage({ type: "success", text: t.portal.studentsPage.activityCreated });
      activities.reload();
    } catch (err) {
      setMessage({
        type: "error",
        text: err instanceof Error && err.message === "NO_STUDENTS_SELECTED" ? t.portal.studentsPage.pickStudents : t.common.tryAgain,
      });
      setActOpen(false);
    } finally {
      setActSaving(false);
    }
  }

  async function removeActivity(a: Activity) {
    if (!(await emsConfirm({ message: t.portal.studentsPage.deleteActivityConfirm, danger: true }))) return;
    try {
      await api(`/api/portal/activities/${a.id}`, { method: "DELETE" });
      setMessage({ type: "success", text: t.portal.studentsPage.activityDeleted });
      activities.reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    }
  }

  function openPhoto(s: Pick<Student, "id" | "name" | "photoUrl">) {
    setPhotoStudent(s);
    setPhotoPreview(null);
  }

  async function handlePhotoFile(file: File | undefined) {
    if (!file) return;
    if (!/^image\/(jpeg|png|webp)$/.test(file.type) || file.size > (uploadPolicy?.imageMaxKb ?? 2048) * 1024) {
      setMessage({ type: "error", text: t.portal.studentsPage.photoInvalid });
      return;
    }
    try {
      setPhotoPreview(await studentPhotoFromFile(file, uploadPolicy?.imageMaxDim ?? 1024));
    } catch {
      setMessage({ type: "error", text: t.portal.studentsPage.photoInvalid });
    }
  }

  async function savePhoto() {
    if (!photoStudent || !photoPreview) return;
    setPhotoSaving(true);
    try {
      await api(`/api/portal/students/${photoStudent.id}/photo`, {
        method: "POST",
        body: JSON.stringify({ photoUrl: photoPreview }),
      });
      setMessage({ type: "success", text: t.portal.studentsPage.photoSaved });
      setPhotoStudent(null);
      setPhotoPreview(null);
      reload();
      if (reportId === photoStudent.id) reportReload();
      sheet.reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setPhotoSaving(false);
    }
  }

  async function removePhoto() {
    if (!photoStudent) return;
    setPhotoSaving(true);
    try {
      await api(`/api/portal/students/${photoStudent.id}/photo`, { method: "DELETE" });
      setMessage({ type: "success", text: t.portal.studentsPage.photoRemoved });
      const id = photoStudent.id;
      setPhotoStudent(null);
      setPhotoPreview(null);
      reload();
      if (reportId === id) reportReload();
      sheet.reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setPhotoSaving(false);
    }
  }


  async function saveAttendance() {
    const entries = Object.entries(attDraft).map(([studentId, status]) => ({
      studentId: Number(studentId),
      status,
    }));
    if (entries.length === 0) return;
    setAttSaving(true);
    try {
      await api("/api/portal/students/attendance", {
        method: "POST",
        body: JSON.stringify({
          date: sheet.data?.date ?? attDate,
          subjectItemId: attSubjectId ? Number(attSubjectId) : null,
          entries,
        }),
      });
      resetAttEdits();
      setMessage({ type: "success", text: t.portal.studentsPage.attendanceSaved });
      sheet.reload();
    } catch {
      setMessage({ type: "error", text: t.common.tryAgain });
    } finally {
      setAttSaving(false);
    }
  }

  // ---- Student list: datagrid update + bulk academic info ----
  const [listClassId, setListClassId] = useState("");
  const [listSectionId, setListSectionId] = useState("");
  const [listShiftId, setListShiftId] = useState("");
  const [picked, setPicked] = useState<Set<number>>(new Set());
  const emptyAcademic = { classItemId: "", sectionItemId: "", shiftItemId: "", groupItemId: "", departmentItemId: "" };
  const [bulkForm, setBulkForm] = useState({ ...emptyAcademic });
  const [bulkSaving, setBulkSaving] = useState(false);
  const [quickEditId, setQuickEditId] = useState<number | null>(null);
  const [quickForm, setQuickForm] = useState({ ...emptyAcademic });
  const [quickSaving, setQuickSaving] = useState(false);

  function togglePick(id: number) {
    setPicked((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }

  /** header checkbox: select / deselect every student on the visible page */
  function togglePickPage() {
    setPicked((prev) => {
      const pageIds = studentsPager.paged.map((s) => s.id);
      const allPicked = pageIds.length > 0 && pageIds.every((id) => prev.has(id));
      const next = new Set(prev);
      for (const id of pageIds) {
        if (allPicked) next.delete(id);
        else next.add(id);
      }
      return next;
    });
  }

  function selectAllFiltered() {
    setPicked(new Set(students.map((s) => s.id)));
  }

  /** Apply the chosen academic info to every selected student. Empty selects
      stay untouched, so a mix of classes can receive e.g. one section/shift. */
  async function applyBulkAcademic() {
    if (picked.size === 0) return;
    const fields: Record<string, number> = {};
    for (const [k, v] of Object.entries(bulkForm)) {
      if (v) fields[k] = Number(v);
    }
    if (Object.keys(fields).length === 0) {
      setMessage({ type: "error", text: t.portal.studentsPage.bulkNoFields });
      return;
    }
    if (!(await emsConfirm({
      message: t.portal.studentsPage.bulkConfirm.replace("{n}", String(picked.size)),
    }))) {
      return;
    }
    setBulkSaving(true);
    try {
      const res = await api<{ updated: number }>("/api/portal/students", {
        method: "PATCH",
        body: JSON.stringify({ studentIds: Array.from(picked), ...fields }),
      });
      setMessage({
        type: "success",
        text: t.portal.studentsPage.academicBulkApplied.replace("{n}", String(res.updated)),
      });
      setPicked(new Set());
      setBulkForm({ ...emptyAcademic });
      reload();
    } catch (err) {
      setMessage({ type: "error", text: err instanceof Error ? err.message : t.common.tryAgain });
    } finally {
      setBulkSaving(false);
    }
  }

  /** Datagrid inline update: edit one student's academic info directly in the list. */
  function openQuickEdit(s: Student) {
    setQuickEditId((cur) => (cur === s.id ? null : s.id));
    setQuickForm({
      classItemId: s.classItemId ? String(s.classItemId) : "",
      sectionItemId: s.sectionItemId ? String(s.sectionItemId) : "",
      shiftItemId: s.shiftItemId ? String(s.shiftItemId) : "",
      groupItemId: s.groupItemId ? String(s.groupItemId) : "",
      departmentItemId: s.departmentItemId ? String(s.departmentItemId) : "",
    });
  }

  async function saveQuickEdit() {
    if (quickEditId == null) return;
    setQuickSaving(true);
    try {
      const payload: Record<string, unknown> = { studentIds: [quickEditId] };
      for (const [k, v] of Object.entries(quickForm)) payload[k] = v ? Number(v) : null;
      await api("/api/portal/students", {
        method: "PATCH",
        body: JSON.stringify(payload),
      });
      setMessage({ type: "success", text: t.portal.studentsPage.academicUpdated });
      setQuickEditId(null);
      reload();
    } catch (err) {
      setMessage({ type: "error", text: err instanceof Error ? err.message : t.common.tryAgain });
    } finally {
      setQuickSaving(false);
    }
  }

  const students = useMemo(() => {
    if (!data) return [];
    let list = data.students;
    if (listClassId) list = list.filter((s) => s.classItemId === Number(listClassId));
    if (listSectionId) list = list.filter((s) => s.sectionItemId === Number(listSectionId));
    if (listShiftId) list = list.filter((s) => s.shiftItemId === Number(listShiftId));
    const q = search.trim().toLowerCase();
    if (!q) return list;
    return list.filter(
      (s) =>
        s.name.toLowerCase().includes(q) ||
        s.roll.toLowerCase().includes(q) ||
        s.guardianName.toLowerCase().includes(q)
    );
  }, [data, search, listClassId, listSectionId, listShiftId]);

  const studentsPager = usePagination(students, 10);

  // Student options for the member-credential manager (student + parent logins)
  const credentialPersons: PersonOption[] = (data?.students ?? []).map((s) => ({
    id: s.id,
    label: s.name,
    sub: `#${s.roll}${s.className ? ` · ${locale === "bn" ? s.classNameBn : s.className}` : ""}`,
    defaultUsername: s.roll,
    defaultName: s.name,
    altName: s.guardianName,
  }));

  const p = report?.student;
  const sheetEntries = sheet.data?.entries ?? [];

  return (
    <div>
      <PageHeader title={t.portal.studentsPage.title} subtitle={t.portal.studentsPage.subtitle} />

      {/* Tabs */}
      <ul className="nav nav-tabs mb-4">
        {([
          { id: "list", label: t.portal.studentsPage.tabStudents },
          { id: "attendance", label: t.portal.studentsPage.tabAttendance },
          { id: "activities", label: t.portal.studentsPage.tabActivities },
          { id: "credentials", label: t.portal.credentials.tabTitle },
        ] as const).map((x) => (
          <li className="nav-item" key={x.id}>
            <button className={`nav-link f-w-600 ${tab === x.id ? "active" : ""}`} type="button" onClick={() => setTab(x.id)}>
              {x.label}
            </button>
          </li>
        ))}
      </ul>

      {message && (
        <div className="mb-4">
          <Alert type={message.type} onClose={() => setMessage(null)}>{message.text}</Alert>
        </div>
      )}

      {tab === "list" &&
        (loading ? (
          <PageLoader text={t.common.loading} />
        ) : !data || data.students.length === 0 ? (
          <div className="card">
            <EmptyState icon={<IconUsers />} title={t.portal.studentsPage.noStudents} />
          </div>
        ) : (
          <div className="card">
            <div className="card-header d-flex flex-wrap align-items-center gap-2">
              <div className="has-search" style={{ flexGrow: 1, maxWidth: 320, minWidth: 200 }}>
                <span className="fa fa-search form-control-feedback" />
                <input
                  className="form-control"
                  placeholder={t.portal.studentsPage.filterLabel}
                  value={search}
                  onChange={(e) => setSearch(e.target.value)}
                />
              </div>
              <div style={{ maxWidth: 160 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={listClassId}
                  onChange={(e) => { setListClassId(e.target.value); setPicked(new Set()); }}
                >
                  <option value="">{t.portal.studentsPage.allClasses}</option>
                  {classItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              <div style={{ maxWidth: 160 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={listSectionId}
                  onChange={(e) => { setListSectionId(e.target.value); setPicked(new Set()); }}
                >
                  <option value="">{t.portal.studentsPage.allSections}</option>
                  {sectionItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              <div style={{ maxWidth: 160 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={listShiftId}
                  onChange={(e) => { setListShiftId(e.target.value); setPicked(new Set()); }}
                >
                  <option value="">{t.portal.studentsPage.allShifts}</option>
                  {shiftItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
            </div>

            {/* bulk academic-info bar — appears when students are selected */}
            {picked.size > 0 && (
              <div
                className="px-3 py-3 border-bottom"
                style={{ background: "rgba(36,105,92,0.05)" }}
              >
                <div className="d-flex flex-wrap align-items-center gap-2">
                  <span className="badge badge-primary ems-fs-12 py-2 px-3">
                    {t.portal.studentsPage.bulkSelected.replace("{n}", String(picked.size))}
                  </span>
                  {picked.size < students.length && (
                    <Button size="sm" variant="info" onClick={selectAllFiltered}>
                      {t.portal.studentsPage.bulkSelectAllFiltered.replace("{n}", String(students.length))}
                    </Button>
                  )}
                  <span className="ems-fs-12 f-w-700 text-muted ms-1">
                    {t.portal.studentsPage.bulkAcademicLabel}
                  </span>
                  <div style={{ maxWidth: 150 }}>
                    <Select
                      wrapperClassName="form-group mb-0"
                      value={bulkForm.classItemId}
                      onChange={(e) => setBulkForm({ ...bulkForm, classItemId: e.target.value })}
                    >
                      <option value="">{t.categories.CLASS} · {t.portal.studentsPage.bulkUnchanged}</option>
                      {classItems.map((c) => (
                        <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                      ))}
                    </Select>
                  </div>
                  <div style={{ maxWidth: 150 }}>
                    <Select
                      wrapperClassName="form-group mb-0"
                      value={bulkForm.sectionItemId}
                      onChange={(e) => setBulkForm({ ...bulkForm, sectionItemId: e.target.value })}
                    >
                      <option value="">{t.categories.SECTION} · {t.portal.studentsPage.bulkUnchanged}</option>
                      {sectionItems.map((c) => (
                        <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                      ))}
                    </Select>
                  </div>
                  <div style={{ maxWidth: 150 }}>
                    <Select
                      wrapperClassName="form-group mb-0"
                      value={bulkForm.shiftItemId}
                      onChange={(e) => setBulkForm({ ...bulkForm, shiftItemId: e.target.value })}
                    >
                      <option value="">{t.categories.SHIFT} · {t.portal.studentsPage.bulkUnchanged}</option>
                      {shiftItems.map((c) => (
                        <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                      ))}
                    </Select>
                  </div>
                  {groupItems.length > 0 && (
                    <div style={{ maxWidth: 150 }}>
                      <Select
                        wrapperClassName="form-group mb-0"
                        value={bulkForm.groupItemId}
                        onChange={(e) => setBulkForm({ ...bulkForm, groupItemId: e.target.value })}
                      >
                        <option value="">{t.categories.GROUP} · {t.portal.studentsPage.bulkUnchanged}</option>
                        {groupItems.map((c) => (
                          <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                        ))}
                      </Select>
                    </div>
                  )}
                  {departmentItems.length > 0 && (
                    <div style={{ maxWidth: 150 }}>
                      <Select
                        wrapperClassName="form-group mb-0"
                        value={bulkForm.departmentItemId}
                        onChange={(e) => setBulkForm({ ...bulkForm, departmentItemId: e.target.value })}
                      >
                        <option value="">{t.categories.DEPARTMENT} · {t.portal.studentsPage.bulkUnchanged}</option>
                        {departmentItems.map((c) => (
                          <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                        ))}
                      </Select>
                    </div>
                  )}
                  <Button size="sm" variant="primary" loading={bulkSaving} onClick={applyBulkAcademic}>
                    <IconLayers className="svg-14" />
                    <span className="ms-1">{t.portal.studentsPage.bulkApply}</span>
                  </Button>
                  <Button size="sm" variant="secondary" onClick={() => setPicked(new Set())}>
                    <IconX className="svg-14" />
                    <span className="ms-1">{t.portal.studentsPage.bulkClear}</span>
                  </Button>
                </div>
              </div>
            )}

            <div className="table-responsive">
              <table className="table table-hover align-middle mb-0">
                <thead className="ems-table-head">
                  <tr>
                    <th style={{ width: 36 }}>
                      <input
                        type="checkbox"
                        className="form-check-input"
                        checked={
                          studentsPager.paged.length > 0 &&
                          studentsPager.paged.every((s) => picked.has(s.id))
                        }
                        onChange={togglePickPage}
                        title={t.portal.studentsPage.bulkSelectAll}
                      />
                    </th>
                    <th>{t.portal.studentsPage.rollNo}</th>
                    <th>{t.common.name}</th>
                    <th>{t.portal.studentsPage.classLabel}</th>
                    <th>{t.portal.studentsPage.guardian}</th>
                    <th>{t.portal.studentsPage.feesDue}</th>
                    <th className="text-end">{t.common.actions}</th>
                  </tr>
                </thead>
                <tbody>
                  {studentsPager.paged.map((s) => (
                    <Fragment key={s.id}>
                      <tr className={quickEditId === s.id ? "table-active" : ""}>
                        <td>
                          <input
                            type="checkbox"
                            className="form-check-input"
                            checked={picked.has(s.id)}
                            onChange={() => togglePick(s.id)}
                          />
                        </td>
                        <td>
                          <span className="ems-roll-badge">{s.roll}</span>
                        </td>
                        <td>
                          <div className="d-flex align-items-center gap-2">
                            <StudentAvatar
                              name={s.name}
                              photoUrl={s.photoUrl}
                              size={40}
                              editable
                              title={t.portal.studentsPage.photoTitle}
                              onClick={() => openPhoto(s)}
                            />
                            <div>
                              <p className="mb-0 f-w-700">{s.name}</p>
                              {s.nameBn && <p className="mb-0 ems-fs-11 text-muted">{s.nameBn}</p>}
                            </div>
                          </div>
                        </td>
                        <td>
                          {s.className ? (
                            <div>
                              <span className="ems-type-pill ems-cat-CLASS">
                                {locale === "bn" ? s.classNameBn : s.className}
                              </span>
                              {s.sectionName && (
                                <p className="mb-0 ems-fs-11 text-muted mt-1">
                                  {t.portal.studentsPage.sectionLabel}: {locale === "bn" ? s.sectionNameBn : s.sectionName}
                                  {s.shiftName ? ` · ${locale === "bn" ? s.shiftNameBn : s.shiftName}` : ""}
                                </p>
                              )}
                            </div>
                          ) : (
                            "—"
                          )}
                        </td>
                        <td>
                          <p className="mb-0 ems-fs-13 f-w-600">{s.guardianName}</p>
                          <p className="mb-0 ems-fs-11 text-muted">{s.guardianPhone}</p>
                        </td>
                        <td>
                          {s.feesDue > 0 ? (
                            <span className="f-w-800 text-danger">{formatBDT(s.feesDue, locale)}</span>
                          ) : (
                            <span className="badge badge-success">
                              {t.central.paymentsPage.fullyPaid}
                            </span>
                          )}
                        </td>
                        <td className="text-end">
                          <div className="d-inline-flex gap-1">
                            <Button
                              size="sm"
                              variant={quickEditId === s.id ? "primary" : "info"}
                              title={t.portal.studentsPage.quickUpdate}
                              onClick={() => openQuickEdit(s)}
                            >
                              <IconLayers className="svg-14" />
                            </Button>
                            <Button size="sm" variant="secondary" onClick={() => setReportId(s.id)}>
                              {t.portal.studentsPage.viewReport}
                            </Button>
                            <Button size="sm" onClick={() => openProfileEditor(s)}>
                              <IconEdit className="svg-14" />
                              <span className="ms-1 d-none d-lg-inline">{t.portal.studentsPage.editProfile}</span>
                            </Button>
                          </div>
                        </td>
                      </tr>
                      {/* datagrid inline edit: update this student's academic info in place */}
                      {quickEditId === s.id && (
                        <tr>
                          <td colSpan={7} style={{ background: "rgba(36,105,92,0.04)" }}>
                            <div className="d-flex flex-wrap align-items-center gap-2 py-1">
                              <span className="ems-fs-12 f-w-700 text-muted me-2">
                                <IconEdit className="svg-14" /> {s.name} — {t.portal.studentsPage.quickUpdate}
                              </span>
                              <div style={{ maxWidth: 160 }}>
                                <Select
                                  wrapperClassName="form-group mb-0"
                                  value={quickForm.classItemId}
                                  onChange={(e) => setQuickForm({ ...quickForm, classItemId: e.target.value })}
                                >
                                  <option value="">— {t.categories.CLASS}</option>
                                  {classItems.map((c) => (
                                    <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                                  ))}
                                </Select>
                              </div>
                              <div style={{ maxWidth: 160 }}>
                                <Select
                                  wrapperClassName="form-group mb-0"
                                  value={quickForm.sectionItemId}
                                  onChange={(e) => setQuickForm({ ...quickForm, sectionItemId: e.target.value })}
                                >
                                  <option value="">— {t.categories.SECTION}</option>
                                  {sectionItems.map((c) => (
                                    <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                                  ))}
                                </Select>
                              </div>
                              <div style={{ maxWidth: 160 }}>
                                <Select
                                  wrapperClassName="form-group mb-0"
                                  value={quickForm.shiftItemId}
                                  onChange={(e) => setQuickForm({ ...quickForm, shiftItemId: e.target.value })}
                                >
                                  <option value="">— {t.categories.SHIFT}</option>
                                  {shiftItems.map((c) => (
                                    <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                                  ))}
                                </Select>
                              </div>
                              {groupItems.length > 0 && (
                                <div style={{ maxWidth: 160 }}>
                                  <Select
                                    wrapperClassName="form-group mb-0"
                                    value={quickForm.groupItemId}
                                    onChange={(e) => setQuickForm({ ...quickForm, groupItemId: e.target.value })}
                                  >
                                    <option value="">— {t.categories.GROUP}</option>
                                    {groupItems.map((c) => (
                                      <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                                    ))}
                                  </Select>
                                </div>
                              )}
                              {departmentItems.length > 0 && (
                                <div style={{ maxWidth: 160 }}>
                                  <Select
                                    wrapperClassName="form-group mb-0"
                                    value={quickForm.departmentItemId}
                                    onChange={(e) => setQuickForm({ ...quickForm, departmentItemId: e.target.value })}
                                  >
                                    <option value="">— {t.categories.DEPARTMENT}</option>
                                    {departmentItems.map((c) => (
                                      <option key={c.id} value={c.id}>{locale === "bn" ? c.nameBn : c.name}</option>
                                    ))}
                                  </Select>
                                </div>
                              )}
                              <Button size="sm" variant="primary" loading={quickSaving} onClick={saveQuickEdit}>
                                <IconCheck className="svg-14" />
                                <span className="ms-1">{t.common.save}</span>
                              </Button>
                              <Button size="sm" variant="secondary" onClick={() => setQuickEditId(null)}>
                                <IconX className="svg-14" />
                                <span className="ms-1">{t.common.cancel}</span>
                              </Button>
                            </div>
                          </td>
                        </tr>
                      )}
                    </Fragment>
                  ))}
                </tbody>
              </table>
            </div>
            <Pagination {...studentsPager} onPageChange={studentsPager.setPage} onSizeChange={studentsPager.setSize} />
          </div>
        ))}

      {/* ---------- Attendance tab ---------- */}
      {tab === "attendance" && (
        <div className="card">
          <div className="card-header d-flex flex-wrap align-items-center justify-content-between gap-2">
            <div className="d-flex flex-wrap align-items-center gap-2">
              <DatePicker
                wrapperClassName="form-group mb-0"
                style={{ maxWidth: 170 }}
                value={attDate}
                onChange={(e) => {
                  setAttDate(e.target.value);
                  resetAttEdits();
                }}
              />
              <div style={{ maxWidth: 170 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={attClassId}
                  onChange={(e) => {
                    setAttClassId(e.target.value);
                    resetAttEdits();
                  }}
                >
                  <option value="">{t.portal.studentsPage.allClasses}</option>
                  {classItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              <div style={{ maxWidth: 170 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={attSectionId}
                  onChange={(e) => {
                    setAttSectionId(e.target.value);
                    resetAttEdits();
                  }}
                >
                  <option value="">{t.portal.studentsPage.allSections}</option>
                  {sectionItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              <div style={{ maxWidth: 170 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={attShiftId}
                  onChange={(e) => {
                    setAttShiftId(e.target.value);
                    resetAttEdits();
                  }}
                >
                  <option value="">{t.portal.studentsPage.allShifts}</option>
                  {shiftItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              <div style={{ maxWidth: 190 }}>
                <Select
                  wrapperClassName="form-group mb-0"
                  value={attSubjectId}
                  onChange={(e) => {
                    setAttSubjectId(e.target.value);
                    resetAttEdits();
                  }}
                >
                  <option value="">{t.portal.studentsPage.subjectOptional}</option>
                  {subjectItems.map((c) => (
                    <option key={c.id} value={c.id}>
                      {locale === "bn" ? c.nameBn : c.name}
                    </option>
                  ))}
                </Select>
              </div>
              {sheet.data && (
                <div className="d-flex flex-wrap gap-1">
                  <span className="badge badge-success">{t.portal.dashboard.present}: {sheet.data.counts.present}</span>
                  <span className="badge badge-danger">{t.portal.dashboard.absent}: {sheet.data.counts.absent}</span>
                  <span className="badge badge-warning">{t.portal.dashboard.onLeave}: {sheet.data.counts.leave}</span>
                </div>
              )}
            </div>
            <div className="d-flex flex-wrap align-items-center gap-2">
              <div className="btn-group btn-group-sm" role="group" aria-label={t.portal.studentsPage.markingMode}>
                <button
                  type="button"
                  className={`btn ${attMode === "individual" ? "btn-primary" : "btn-outline-secondary"}`}
                  onClick={() => setAttMode("individual")}
                >
                  {t.portal.studentsPage.modeIndividual}
                </button>
                <button
                  type="button"
                  className={`btn ${attMode === "bulk" ? "btn-primary" : "btn-outline-secondary"}`}
                  onClick={() => setAttMode("bulk")}
                >
                  {t.portal.studentsPage.modeBulk}
                </button>
              </div>
              <Button onClick={saveAttendance} loading={attSaving} disabled={Object.keys(attDraft).length === 0}>
                <IconCheck className="svg-16" />
                <span className="ms-1">{t.portal.studentsPage.markAttendance}</span>
              </Button>
            </div>
          </div>
          <div className="card-body py-2">
            <p className="mb-0 ems-fs-11 text-muted">
              {attMode === "individual"
                ? `${t.portal.studentsPage.attendanceHint} ${t.portal.studentsPage.subjectHint}`
                : `${t.portal.studentsPage.bulkHint} ${t.portal.studentsPage.subjectHint}`}
            </p>
          </div>
          {sheet.loading && !sheet.data ? (
            <div className="card-body text-center py-4">
              <span className="spinner-border text-primary" role="status" />
            </div>
          ) : sheetEntries.length === 0 ? (
            <div className="card-body">
              <EmptyState icon={<IconUsers />} title={t.portal.studentsPage.noStudents} />
            </div>
          ) : attMode === "individual" ? (
            <div className="table-responsive">
              <table className="table table-hover align-middle mb-0">
                <thead className="ems-table-head">
                  <tr>
                    <th style={{ width: 60 }}>{t.portal.studentsPage.photoCol}</th>
                    <th>{t.portal.studentsPage.rollNo}</th>
                    <th>{t.common.name}</th>
                    <th>{t.portal.studentsPage.classLabel}</th>
                    <th className="text-end">{t.common.status}</th>
                  </tr>
                </thead>
                <tbody>
                  {sheetEntries.map((e) => {
                    const current = attDraft[e.studentId] ?? e.status;
                    return (
                      <tr key={e.studentId}>
                        <td>
                          <StudentAvatar name={e.name} photoUrl={e.photoUrl} size={40} />
                        </td>
                        <td>
                          <span className="ems-roll-badge">{e.roll}</span>
                        </td>
                        <td>
                          <span className="f-w-600">
                            {e.name}
                            {e.nameBn && <span className="ms-1 ems-fs-11 text-muted f-w-500">({e.nameBn})</span>}
                          </span>
                          {e.source === "DEVICE" && e.inTime && (
                            <div className="ems-fs-11 text-muted mt-1">
                              <span className="badge badge-soft-teal me-1">{t.me.deviceBadge}</span>
                              {formatTime(e.inTime, locale)}
                              {e.outTime && e.outTime !== e.inTime ? ` → ${formatTime(e.outTime, locale)}` : ""}
                            </div>
                          )}
                        </td>
                        <td className="ems-fs-13">
                          {e.className ? (locale === "bn" ? e.classNameBn ?? e.className : e.className) : "—"}
                        </td>
                        <td className="text-end">
                          <div className="btn-group btn-group-sm" role="group">
                            {ATTENDANCE_STATUSES.map((st) => (
                              <button
                                key={st}
                                type="button"
                                className={`btn ${
                                  current === st
                                    ? st === "PRESENT"
                                      ? "btn-success"
                                      : st === "ABSENT"
                                        ? "btn-danger"
                                        : "btn-warning"
                                    : "btn-outline-secondary"
                                }`}
                                onClick={() => setAttDraft({ ...attDraft, [e.studentId]: st })}
                              >
                                {t.status[st as keyof typeof t.status]}
                              </button>
                            ))}
                          </div>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          ) : (
            <>
              {/* Bulk toolbar — select students, then apply a status to all of them */}
              <div className="card-body py-2 border-bottom d-flex flex-wrap align-items-center gap-2">
                <span className="badge badge-primary">
                  {bulkPicked.size} {t.portal.studentsPage.selectedLabel}
                </span>
                <span className="ems-fs-12 text-muted f-w-600">{t.portal.studentsPage.applyToSelected}</span>
                <div className="btn-group btn-group-sm" role="group">
                  <button
                    type="button"
                    className="btn btn-success"
                    disabled={bulkPicked.size === 0}
                    onClick={() => applyBulkStatus("PRESENT")}
                  >
                    {t.status.PRESENT}
                  </button>
                  <button
                    type="button"
                    className="btn btn-danger"
                    disabled={bulkPicked.size === 0}
                    onClick={() => applyBulkStatus("ABSENT")}
                  >
                    {t.status.ABSENT}
                  </button>
                  <button
                    type="button"
                    className="btn btn-warning"
                    disabled={bulkPicked.size === 0}
                    onClick={() => applyBulkStatus("LEAVE")}
                  >
                    {t.status.LEAVE}
                  </button>
                </div>
                <button
                  type="button"
                  className="btn btn-sm btn-outline-secondary"
                  disabled={bulkPicked.size === 0}
                  onClick={() => setBulkPicked(new Set())}
                >
                  {t.portal.studentsPage.clearSelection}
                </button>
                {Object.keys(attDraft).length > 0 && (
                  <span className="ms-auto ems-fs-11 text-muted">
                    {Object.keys(attDraft).length} {t.portal.studentsPage.bulkApplied}
                  </span>
                )}
              </div>
              <div className="table-responsive">
                <table className="table table-hover align-middle mb-0">
                  <thead className="ems-table-head">
                    <tr>
                      <th style={{ width: 36 }}>
                        <input
                          type="checkbox"
                          className="form-check-input mt-0"
                          aria-label={t.portal.studentsPage.selectAll}
                          title={t.portal.studentsPage.selectAll}
                          checked={bulkPicked.size > 0 && bulkPicked.size === sheetEntries.length}
                          ref={(el) => {
                            if (el) el.indeterminate = bulkPicked.size > 0 && bulkPicked.size < sheetEntries.length;
                          }}
                          onChange={() =>
                            setBulkPicked(
                              bulkPicked.size === sheetEntries.length
                                ? new Set()
                                : new Set(sheetEntries.map((e) => e.studentId))
                            )
                          }
                        />
                      </th>
                      <th style={{ width: 60 }}>{t.portal.studentsPage.photoCol}</th>
                      <th>{t.portal.studentsPage.rollNo}</th>
                      <th>{t.common.name}</th>
                      <th>{t.portal.studentsPage.classLabel}</th>
                      <th className="text-end">{t.common.status}</th>
                    </tr>
                  </thead>
                  <tbody>
                    {sheetEntries.map((e) => {
                      const current = attDraft[e.studentId] ?? e.status;
                      const picked = bulkPicked.has(e.studentId);
                      return (
                        <tr key={e.studentId} className={picked ? "table-active" : ""}>
                          <td>
                            <input
                              type="checkbox"
                              className="form-check-input mt-0"
                              aria-label={e.name}
                              checked={picked}
                              onChange={() => toggleBulkPick(e.studentId)}
                            />
                          </td>
                          <td>
                            <StudentAvatar name={e.name} photoUrl={e.photoUrl} size={40} />
                          </td>
                          <td>
                            <span className="ems-roll-badge">{e.roll}</span>
                          </td>
                          <td>
                            <span className="f-w-600">
                              {e.name}
                              {e.nameBn && <span className="ms-1 ems-fs-11 text-muted f-w-500">({e.nameBn})</span>}
                            </span>
                          </td>
                          <td className="ems-fs-13">
                            {e.className ? (locale === "bn" ? e.classNameBn ?? e.className : e.className) : "—"}
                          </td>
                          <td className="text-end">
                            {current ? (
                              <span
                                className={`badge ${
                                  current === "PRESENT" ? "badge-success" : current === "ABSENT" ? "badge-danger" : "badge-warning"
                                }`}
                              >
                                {t.status[current as keyof typeof t.status]}
                              </span>
                            ) : (
                              <span className="badge badge-light">{t.portal.studentsPage.unmarked}</span>
                            )}
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </>
          )}
        </div>
      )}

      {/* ---------- Activities tab ---------- */}
      {tab === "activities" && (
        <div className="card">
          <div className="card-header d-flex flex-wrap align-items-center justify-content-between gap-2">
            <h5 className="mb-0 f-w-700">{t.portal.studentsPage.tabActivities}</h5>
            <Button size="sm" onClick={() => setActOpen(true)}>
              <IconPlus className="svg-16" />
              <span className="ms-1">{t.portal.studentsPage.newActivity}</span>
            </Button>
          </div>
          {activities.loading && !activities.data ? (
            <div className="card-body text-center py-4">
              <span className="spinner-border text-primary" role="status" />
            </div>
          ) : !activities.data || activities.data.activities.length === 0 ? (
            <div className="card-body">
              <EmptyState icon={<IconUsers />} title={t.portal.studentsPage.noActivities} />
            </div>
          ) : (
            <div className="table-responsive">
              <table className="table table-hover align-middle mb-0">
                <thead className="ems-table-head">
                  <tr>
                    <th>{t.portal.studentsPage.activityDate}</th>
                    <th>{t.portal.studentsPage.activityTitle}</th>
                    <th>{t.portal.studentsPage.audience}</th>
                    <th className="text-end">{t.common.actions}</th>
                  </tr>
                </thead>
                <tbody>
                  {activitiesPager.paged.map((a) => (
                    <tr key={a.id}>
                      <td className="ems-fs-12 text-muted">{formatDate(a.activityDate, locale)}</td>
                      <td>
                        <p className="mb-0 f-w-700 ems-fs-13">{a.title}</p>
                        {a.description && <p className="mb-0 ems-fs-11 text-muted text-truncate" style={{ maxWidth: 420 }}>{a.description}</p>}
                        {a.createdByName && (
                          <p className="mb-0 ems-fs-11 text-muted">— {a.createdByName}</p>
                        )}
                      </td>
                      <td>
                        {a.isForAll ? (
                          <span className="badge badge-primary">{t.portal.studentsPage.audienceAll}</span>
                        ) : (
                          <div>
                            <span className="badge badge-secondary">{a.recipientCount} {t.portal.studentsPage.recipientsLabel}</span>
                            {a.recipients.length > 0 && (
                              <p className="mb-0 ems-fs-11 text-muted mt-1">
                                {a.recipients.map((r) => `${r.name} (${r.roll})`).join(", ")}
                              </p>
                            )}
                          </div>
                        )}
                      </td>
                      <td className="text-end">
                        <Button size="sm" variant="danger" onClick={() => removeActivity(a)} title={t.common.delete}>
                          <IconTrash className="svg-16" />
                        </Button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
          <Pagination {...activitiesPager} onPageChange={activitiesPager.setPage} onSizeChange={activitiesPager.setSize} />
        </div>
      )}

      {/* ---------- Credentials tab (student & parent logins) ---------- */}
      {tab === "credentials" && (
        <CredentialsPanel roles={["STUDENT", "PARENT"]} students={credentialPersons} />
      )}

      {/* New activity modal */}
      <Modal open={actOpen} onClose={() => setActOpen(false)} title={t.portal.studentsPage.newActivity} wide>
        <form className="theme-form" onSubmit={submitActivity}>
          <div className="row">
            <div className="col-md-8">
              <Input
                label={t.portal.studentsPage.activityTitle}
                required
                value={actForm.title}
                onChange={(e) => setActForm({ ...actForm, title: e.target.value })}
              />
            </div>
            <div className="col-md-4">
              <DatePicker
                label={t.portal.studentsPage.activityDate}
                value={actForm.date}
                onChange={(e) => setActForm({ ...actForm, date: e.target.value })}
              />
            </div>
            <div className="col-md-12">
              <Textarea
                label={t.portal.studentsPage.activityNote}
                value={actForm.description}
                onChange={(e) => setActForm({ ...actForm, description: e.target.value })}
              />
            </div>
            <div className="col-md-12">
              <Select
                label={t.portal.studentsPage.audience}
                value={actForm.target}
                onChange={(e) => setActForm({ ...actForm, target: e.target.value as "ALL" | "SELECTED" })}
              >
                <option value="ALL">{t.portal.studentsPage.targetAll}</option>
                <option value="SELECTED">{t.portal.studentsPage.targetSelected}</option>
              </Select>
            </div>
          </div>
          {actForm.target === "SELECTED" && (
            <div className="mb-3">
              <label className="col-form-label pt-0 f-w-600">
                {t.portal.studentsPage.pickStudents}
                <span className="text-muted f-w-500 ms-1">({actPicked.size})</span>
              </label>
              <div style={{ maxHeight: "34vh", overflowY: "auto" }} className="border rounded p-2">
                {(data?.students ?? []).map((s) => (
                  <label className="d-flex align-items-center gap-2 ems-fs-13 mb-2 cursor-pointer" key={s.id}>
                    <input
                      type="checkbox"
                      className="form-check-input mt-0"
                      checked={actPicked.has(s.id)}
                      onChange={() => togglePicked(s.id)}
                    />
                    <StudentAvatar name={s.name} photoUrl={s.photoUrl} size={26} />
                    <span>
                      <span className="f-w-600">{s.name}</span>{" "}
                      <span className="text-muted">({s.roll}{s.className ? ` · ${locale === "bn" ? s.classNameBn : s.className}` : ""})</span>
                    </span>
                  </label>
                ))}
              </div>
            </div>
          )}
          <div className="d-flex justify-content-end gap-2">
            <Button type="button" variant="secondary" onClick={() => setActOpen(false)}>
              {t.common.cancel}
            </Button>
            <Button
              type="submit"
              loading={actSaving}
              disabled={!actForm.title.trim() || !actForm.date || (actForm.target === "SELECTED" && actPicked.size === 0)}
            >
              {t.common.save}
            </Button>
          </div>
        </form>
      </Modal>

      {/* Student profile report modal */}
      <Modal
        open={reportId !== null}
        onClose={() => setReportId(null)}
        title={t.portal.studentsPage.profileReport}
        wide
      >
        {reportLoading || !p ? (
          <div className="text-center py-4">
            <span className="spinner-border text-primary" role="status" />
          </div>
        ) : (
          <div>
            {/* Student info */}
            <div className="d-flex align-items-center gap-3 mb-3 p-3 rounded" style={{ background: "rgba(36,105,92,0.07)" }}>
              <StudentAvatar
                name={p.name}
                photoUrl={p.photoUrl}
                size={56}
                editable
                title={t.portal.studentsPage.photoChange}
                onClick={() => openPhoto({ id: p.id, name: p.name, photoUrl: p.photoUrl })}
              />
              <div className="flex-grow-1">
                <h5 className="mb-0 f-w-800">
                  {p.name} {p.nameBn ? <span className="text-muted f-w-500">({p.nameBn})</span> : null}
                </h5>
                <p className="mb-0 ems-fs-12 text-muted">
                  {t.portal.studentsPage.rollNo}: <b>{p.roll}</b>
                  {p.registrationNo ? ` · ${t.portal.identityPage.registrationNo}: ${p.registrationNo}` : ""}
                  {p.cardNo ? ` · ${t.portal.identityPage.cardNo}: ${p.cardNo}` : ""}
                  {p.bloodGroup ? ` · ${t.portal.admissionsPage.bloodGroup}: ${p.bloodGroup}` : ""}
                  {p.className ? ` · ${t.portal.studentsPage.classLabel}: ${locale === "bn" ? p.classNameBn : p.className}` : ""}
                  {p.sectionName ? ` · ${locale === "bn" ? p.sectionNameBn : p.sectionName}` : ""}
                </p>
                <p className="mb-0 ems-fs-12 text-muted">
                  {t.portal.studentsPage.guardian}: {p.guardianName} · {p.guardianPhone}
                </p>
                <p className="mb-0 ems-fs-12 text-muted">
                  {t.portal.studentsPage.admittedOn}: {formatDate(p.admittedOn, locale)}
                </p>
              </div>
            </div>

            {/* Totals */}
            <div className="row g-2 text-center mb-3">
              <div className="col-4">
                <div className="p-2 rounded ems-bg-soft">
                  <p className="mb-0 ems-fs-11 f-w-700 text-muted">{t.portal.studentsPage.totalAssigned}</p>
                  <p className="mb-0 f-w-800">{formatBDT(report.totals.assigned, locale)}</p>
                </div>
              </div>
              <div className="col-4">
                <div className="p-2 rounded" style={{ background: "rgba(40,167,69,0.09)" }}>
                  <p className="mb-0 ems-fs-11 f-w-700 text-success">{t.portal.dashboard.totalPaid}</p>
                  <p className="mb-0 f-w-800 text-success">{formatBDT(report.totals.paid, locale)}</p>
                </div>
              </div>
              <div className="col-4">
                <div className="p-2 rounded" style={{ background: "rgba(232,74,91,0.09)" }}>
                  <p className="mb-0 ems-fs-11 f-w-700 text-danger">{t.portal.dashboard.outstandingDue}</p>
                  <p className="mb-0 f-w-800 text-danger">{formatBDT(report.totals.due, locale)}</p>
                </div>
              </div>
            </div>

            {/* Fee statement */}
            <h6 className="f-w-700 mb-2">{t.portal.studentsPage.feeStatement}</h6>
            {report.schedules.length === 0 ? (
              <EmptyState title={t.common.noData} />
            ) : (
              <div className="table-responsive">
                <table className="table table-sm table-hover align-middle mb-0">
                  <thead className="ems-table-head">
                    <tr>
                      <th>{t.portal.feesPage.feeTitle}</th>
                      <th>{t.common.amount}</th>
                      <th>{t.portal.feesPage.collectedTotal}</th>
                      <th>{t.common.due}</th>
                      <th>{t.common.status}</th>
                    </tr>
                  </thead>
                  <tbody>
                    {report.schedules.map((fs) => (
                      <tr key={fs.id}>
                        <td>
                          <p className="mb-0 ems-fs-13 f-w-600">{fs.title}</p>
                          <p className="mb-0 ems-fs-11 text-muted">
                            {locale === "bn" ? fs.headNameBn : fs.headName} · {formatDate(fs.dueDate, locale)}
                          </p>
                        </td>
                        <td className="f-w-700">{formatBDT(fs.amount, locale)}</td>
                        <td className="text-success">{formatBDT(fs.paid, locale)}</td>
                        <td className={fs.due > 0 ? "text-danger f-w-700" : ""}>{formatBDT(fs.due, locale)}</td>
                        <td>
                          <StatusBadge
                            status={fs.status}
                            label={fs.status === "PAID" ? t.common.paid : fs.status === "PARTIAL" ? "PARTIAL" : t.common.due}
                          />
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        )}
      </Modal>

      {/* Student profile photo modal */}
      <Modal
        open={photoStudent !== null}
        onClose={() => {
          setPhotoStudent(null);
          setPhotoPreview(null);
        }}
        title={t.portal.studentsPage.photoTitle}
      >
        {photoStudent && (
          <div className="text-center">
            <div className="mb-3 d-flex justify-content-center">
              <StudentAvatar name={photoStudent.name} photoUrl={photoPreview ?? photoStudent.photoUrl} size={120} />
            </div>
            <p className="mb-1 f-w-700">{photoStudent.name}</p>
            <p className="mb-3 ems-fs-12 text-muted">{t.portal.studentsPage.photoHint}</p>
            <input
              ref={photoInputRef}
              type="file"
              accept="image/jpeg,image/png,image/webp"
              className="d-none"
              onChange={(e) => {
                handlePhotoFile(e.target.files?.[0]);
                e.target.value = "";
              }}
            />
            <div className="d-flex flex-wrap justify-content-center gap-2">
              <Button variant="secondary" onClick={() => photoInputRef.current?.click()}>
                <IconCamera className="svg-16" />
                <span className="ms-1">
                  {photoPreview || photoStudent.photoUrl
                    ? t.portal.studentsPage.photoChange
                    : t.portal.studentsPage.photoUpload}
                </span>
              </Button>
              {photoStudent.photoUrl && (
                <Button variant="danger" onClick={removePhoto} disabled={photoSaving}>
                  <IconTrash className="svg-16" />
                  <span className="ms-1">{t.portal.studentsPage.photoRemove}</span>
                </Button>
              )}
              {photoPreview && (
                <Button onClick={savePhoto} loading={photoSaving}>
                  {t.common.save}
                </Button>
              )}
            </div>
          </div>
        )}
      </Modal>

      {/* ---------- Student profile editor ---------- */}
      <Modal
        open={!!profileEditor}
        onClose={() => setProfileEditor(null)}
        title={`${t.portal.studentsPage.editProfile} — ${profileEditor?.name ?? ""}`}
        wide
      >
        {profileEditor && (
          <form className="theme-form" onSubmit={saveProfile}>
            <div className="row">
              <div className="col-md-4">
                <label className="col-form-label pt-0 f-w-600">
                  {t.portal.studentsPage.photoLabel}
                </label>
                <div className="d-flex flex-column align-items-start gap-2 pt-1">
                  {profileForm.photoUrl ? (
                    <img
                      src={profileForm.photoUrl}
                      alt=""
                      style={{ width: 96, height: 112, objectFit: "cover" }}
                      className="rounded border"
                    />
                  ) : (
                    <div
                      className="rounded border d-flex align-items-center justify-content-center text-muted"
                      style={{ width: 96, height: 112 }}
                    >
                      <IconCamera className="svg-24" />
                    </div>
                  )}
                  <div className="d-flex gap-2">
                    <label className="btn btn-sm btn-outline-primary f-w-600 cursor-pointer mb-0">
                      {t.portal.studentsPage.choosePhoto}
                      <input type="file" accept="image/*" hidden onChange={onPhotoPick} />
                    </label>
                    {profileForm.photoUrl && (
                      <button
                        type="button"
                        className="btn btn-sm btn-outline-danger f-w-600"
                        onClick={() => setProfileForm((f) => ({ ...f, photoUrl: "" }))}
                      >
                        {t.portal.studentsPage.photoRemove}
                      </button>
                    )}
                  </div>
                </div>
              </div>
              <div className="col-md-8">
                <h6 className="f-w-700 mb-3">{t.portal.studentsPage.personalInfo}</h6>
                <div className="row">
                  <div className="col-md-6">
                    <Input
                      label={t.common.name}
                      required
                      value={profileForm.name}
                      onChange={(e) => setProfileForm({ ...profileForm, name: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.studentsPage.nameBnLabel}
                      value={profileForm.nameBn}
                      onChange={(e) => setProfileForm({ ...profileForm, nameBn: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Select
                      label={t.portal.admissionsPage.gender}
                      value={profileForm.gender}
                      onChange={(e) => setProfileForm({ ...profileForm, gender: e.target.value })}
                    >
                      <option value="MALE">{t.portal.admissionsPage.male}</option>
                      <option value="FEMALE">{t.portal.admissionsPage.female}</option>
                      <option value="OTHER">{t.portal.admissionsPage.other}</option>
                    </Select>
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.admissionsPage.dob}
                      type="date"
                      value={profileForm.dob}
                      onChange={(e) => setProfileForm({ ...profileForm, dob: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Select
                      label={`${t.categories.GROUP} (${t.portal.controlPanelPage.gsGroupLevel})`}
                      value={profileForm.groupId}
                      onChange={(e) => setProfileForm({ ...profileForm, groupId: e.target.value })}
                    >
                      <option value="">—</option>
                      {(academic.data?.items ?? []).filter((i) => i.category === "GROUP").map((g) => (
                        <option key={g.id} value={g.id}>{locale === "bn" ? g.nameBn : g.name}</option>
                      ))}
                    </Select>
                  </div>
                  <div className="col-md-6">
                    <Select
                      label={`${t.categories.DEPARTMENT} (${t.portal.controlPanelPage.gsDeptLevel})`}
                      value={profileForm.departmentId}
                      onChange={(e) => setProfileForm({ ...profileForm, departmentId: e.target.value })}
                    >
                      <option value="">—</option>
                      {(academic.data?.items ?? []).filter((i) => i.category === "DEPARTMENT").map((d) => (
                        <option key={d.id} value={d.id}>{locale === "bn" ? d.nameBn : d.name}</option>
                      ))}
                    </Select>
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.admissionsPage.guardianName}
                      required
                      value={profileForm.guardianName}
                      onChange={(e) => setProfileForm({ ...profileForm, guardianName: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.admissionsPage.guardianNameBn}
                      value={profileForm.guardianNameBn}
                      onChange={(e) => setProfileForm({ ...profileForm, guardianNameBn: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.admissionsPage.guardianPhone}
                      required
                      value={profileForm.guardianPhone}
                      onChange={(e) => setProfileForm({ ...profileForm, guardianPhone: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.studentsPage.motherName}
                      value={profileForm.motherName}
                      onChange={(e) => setProfileForm({ ...profileForm, motherName: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.admissionsPage.motherNameBn}
                      value={profileForm.motherNameBn}
                      onChange={(e) => setProfileForm({ ...profileForm, motherNameBn: e.target.value })}
                    />
                  </div>
                  <div className="col-md-6">
                    <Input
                      label={t.portal.studentsPage.addressLabel}
                      value={profileForm.address}
                      onChange={(e) => setProfileForm({ ...profileForm, address: e.target.value })}
                    />
                  </div>
                </div>
              </div>
              <div className="col-12">
                <h6 className="f-w-700 mb-1">{t.portal.studentsPage.optionalSubjects}</h6>
                <p className="mb-0 ems-fs-12 text-muted mb-2">
                  {t.portal.studentsPage.optionalSubjectsHint}
                </p>
                <div className="d-flex flex-wrap gap-2">
                  {(((poolData?.byClass ?? {})[profileEditor.classItemId ?? -1]) ?? []).map((sub) => {
                    const on = pickedSubjects.includes(sub.id);
                    return (
                      <button
                        type="button"
                        key={sub.id}
                        className={`btn btn-sm f-w-600 ${on ? "btn-primary" : "btn-outline-secondary"}`}
                        onClick={() =>
                          setPickedSubjects((prev) =>
                            on ? prev.filter((x) => x !== sub.id) : [...prev, sub.id]
                          )
                        }
                      >
                        {on && <IconCheck className="svg-12 me-1" />}
                        {locale === "bn" ? sub.nameBn : sub.name}
                      </button>
                    );
                  })}
                  {((poolData?.byClass ?? {})[profileEditor.classItemId ?? -1])?.length === 0 && (
                    <span className="text-muted ems-fs-12">
                      {t.portal.studentsPage.optionalPoolEmpty}
                    </span>
                  )}
                </div>
              </div>
            </div>
            <div className="col-12">
              <h6 className="f-w-700 mb-1">{t.portal.studentsPage.mediaTitle}</h6>
              <p className="mb-2 ems-fs-12 text-muted">{t.portal.studentsPage.mediaHint}</p>
              <div className="ems-media-grid">
                {[
                  { kind: "STUDENT_ID", label: t.portal.studentsPage.mediaStudentId },
                  { kind: "FATHER_NID", label: t.portal.studentsPage.mediaFatherNid },
                  { kind: "MOTHER_NID", label: t.portal.studentsPage.mediaMotherNid },
                ].map((doc) =>
                  (["FRONT", "BACK"] as const).map((side) => {
                    const key = `${doc.kind}_${side}`;
                    const url = mediaMap[key];
                    return (
                      <div className="ems-media-slot" key={key}>
                        <div className="ems-media-head">
                          <span className="k">{doc.label}</span>
                          <span className="s">
                            {side === "FRONT"
                              ? t.portal.studentsPage.sideFront
                              : t.portal.studentsPage.sideBack}
                          </span>
                        </div>
                        <div className={`ems-media-thumb${url ? "" : " empty"}`}>
                          {url ? (
                            <img src={url} alt="" onClick={() => setMediaViewer({ key, dataUrl: url })} />
                          ) : (
                            <span className="empty-lbl">{t.portal.studentsPage.mediaEmpty}</span>
                          )}
                          {mediaBusy === key && <span className="ems-media-busy"><Spinner /></span>}
                        </div>
                        <div className="ems-media-acts">
                          <label className="btn btn-sm btn-outline-primary f-w-600 cursor-pointer mb-0">
                            {url ? t.portal.studentsPage.mediaReplace : t.portal.studentsPage.mediaUpload}
                            <input
                              type="file"
                              accept="image/*"
                              hidden
                              onChange={(e) => {
                                const f = e.target.files?.[0];
                                if (f) uploadMedia(key, f);
                                e.target.value = "";
                              }}
                            />
                          </label>
                          {url && (
                            <>
                              <button
                                type="button"
                                className="btn btn-sm btn-soft-secondary f-w-600"
                                onClick={() => setMediaViewer({ key, dataUrl: url })}
                              >
                                {t.portal.studentsPage.mediaView}
                              </button>
                              <button
                                type="button"
                                className="btn btn-sm btn-soft-danger f-w-600"
                                onClick={() => removeMedia(key)}
                              >
                                {t.portal.studentsPage.mediaRemove}
                              </button>
                            </>
                          )}
                        </div>
                      </div>
                    );
                  })
                )}
              </div>
            </div>
            <div className="d-flex justify-content-end gap-2 pt-3">
              <Button type="button" variant="secondary" onClick={() => setProfileEditor(null)}>
                {t.common.cancel}
              </Button>
              <Button type="submit" loading={profileSaving}>
                {t.common.saveChanges}
              </Button>
            </div>
          </form>
        )}
      </Modal>

      {/* Media viewer — large preview with download for authorized users */}
      <Modal
        open={!!mediaViewer}
        onClose={() => setMediaViewer(null)}
        title={t.portal.studentsPage.mediaTitle}
        wide
      >
        {mediaViewer && (
          <div className="text-center">
            <img
              src={mediaViewer.dataUrl}
              alt=""
              style={{ maxWidth: "100%", borderRadius: 10, border: "1px solid #e2e8e6" }}
            />
            <div className="d-flex justify-content-center gap-2 pt-3">
              <a
                className="btn btn-primary f-w-700"
                download={`${profileEditor?.roll ?? "student"}-${mediaViewer.key.toLowerCase()}.jpg`}
                href={mediaViewer.dataUrl}
              >
                <IconDownload className="svg-16" />
                <span className="ms-1">{t.portal.studentsPage.mediaDownload}</span>
              </a>
            </div>
          </div>
        )}
      </Modal>
    </div>
  );
}
