import { useMemo, useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { ClipboardCheck, GraduationCap, Loader2, Users } from 'lucide-react';

import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Label } from '@/components/ui/label';
import { ModuleHeader } from '@/components/ui/module-header';
import { PageSkeleton } from '@/components/ui/page-skeleton';
import { useAuth } from '@/contexts/useAuth';
import {
  getClass,
  getClassAttendanceSummary,
  listGuardianStudents,
  listUsers,
  type AdminUserRow,
  upsertClassAttendance,
} from '@/business/my-class/api';
import { getErrorMessage } from '@/shared/errors/errorMessages';

function personName(row: { firstName?: string | null; lastName?: string | null; email?: string }): string {
  return [row.firstName, row.lastName].filter(Boolean).join(' ').trim() || row.email || '—';
}

const today = () => new Date().toISOString().slice(0, 10);

type StudentAttendanceStatus = 'present' | 'late' | 'absent';

const STUDENT_ATTENDANCE_STATUS_OPTIONS: readonly {
  value: StudentAttendanceStatus;
  label: string;
}[] = [
  { value: 'present', label: 'Present' },
  { value: 'late', label: 'Late' },
  { value: 'absent', label: 'Absent' },
];

function reconcileStudentStatuses(
  current: Record<string, StudentAttendanceStatus>,
  students: readonly AdminUserRow[],
): Record<string, StudentAttendanceStatus> {
  const next: Record<string, StudentAttendanceStatus> = {};
  for (const student of students) {
    next[student.id] = current[student.id] ?? 'present';
  }
  return next;
}

export default function MyClassPage() {
  const { user } = useAuth();
  const queryClient = useQueryClient();
  const classId = user?.classId ?? null;
  const canFill = (user?.permissions ?? []).includes('FILL_ATTENDANCE');

  const classQuery = useQuery({
    queryKey: ['my-class', classId],
    queryFn: () => getClass(classId as string),
    enabled: Boolean(classId),
  });
  const membersQuery = useQuery({
    queryKey: ['my-class-members', classId],
    queryFn: () => listUsers({ classId: classId as string }),
    enabled: Boolean(classId),
  });
  const guardiansQuery = useQuery({
    queryKey: ['my-class-guardians'],
    queryFn: () => listGuardianStudents(),
    enabled: Boolean(classId),
  });
  const summaryQuery = useQuery({
    queryKey: ['my-class-attendance', classId],
    queryFn: () => getClassAttendanceSummary(),
    enabled: Boolean(classId),
  });

  const members = useMemo(
    () => membersQuery.data?.rows ?? [],
    [membersQuery.data],
  );
  const students = useMemo(
    () => members.filter((m) => m.app_role?.name === 'student'),
    [members],
  );
  const staff = useMemo(
    () => members.filter((m) => m.app_role?.name === 'teacher' || m.app_role?.name === 'support_staff'),
    [members],
  );

  // studentId → guardian display names.
  const guardiansByStudent = useMemo(() => {
    const map = new Map<string, string[]>();
    for (const row of guardiansQuery.data?.rows ?? []) {
      const name = row.guardian ? personName(row.guardian) : null;
      if (!name) continue;
      const list = map.get(row.studentId) ?? [];
      list.push(name);
      map.set(row.studentId, list);
    }
    return map;
  }, [guardiansQuery.data]);

  const [date, setDate] = useState(today());
  const [studentStatusOverrides, setStudentStatusOverrides] = useState<Record<string, StudentAttendanceStatus>>({});
  const [saving, setSaving] = useState(false);
  const [status, setStatus] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
  const studentStatuses = useMemo(
    () => reconcileStudentStatuses(studentStatusOverrides, students),
    [studentStatusOverrides, students],
  );

  async function handleAttendance() {
    setStatus(null);
    if (!classId) return;
    if (students.length === 0) {
      setStatus({ type: 'error', text: 'No students are available for attendance.' });
      return;
    }

    const totalPresent = students.filter((student) => (
      (studentStatuses[student.id] ?? 'present') !== 'absent'
    )).length;
    const totalAbsent = students.filter((student) => (
      (studentStatuses[student.id] ?? 'present') === 'absent'
    )).length;
    const totalTardy = students.filter((student) => (
      (studentStatuses[student.id] ?? 'present') === 'late'
    )).length;

    setSaving(true);
    try {
      await upsertClassAttendance(classId, date, {
        total_enrolled: students.length,
        total_present: totalPresent,
        total_absent: totalAbsent,
        total_tardy: totalTardy,
      });
      await queryClient.invalidateQueries({ queryKey: ['my-class-attendance', classId] });
      setStatus({ type: 'success', text: 'Attendance saved.' });
    } catch (error) {
      setStatus({ type: 'error', text: getErrorMessage(error, 'Could not save attendance') });
    } finally {
      setSaving(false);
    }
  }

  if (!classId) {
    return (
      <div className="p-4 md:p-6">
        <div className="rounded-lg border border-slate-700/50 bg-slate-800/40 px-4 py-3 text-sm text-slate-300">
          You are not assigned to a class yet.
        </div>
      </div>
    );
  }

  if (classQuery.isLoading || membersQuery.isLoading) {
    return <PageSkeleton />;
  }

  return (
    <div className="space-y-6 p-4 md:p-6">
      <ModuleHeader
        title={classQuery.data?.name ?? 'My Class'}
        description="Your class roster and daily attendance."
        icon={GraduationCap}
        iconClassName="bg-gradient-to-br from-lime-500 to-lime-700"
      />

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
        <Card className="lg:col-span-2">
          <CardHeader>
            <CardTitle className="flex items-center gap-2 text-base">
              <Users size={16} />
              Students ({students.length})
            </CardTitle>
          </CardHeader>
          <CardContent>
            {students.length === 0 ? (
              <p className="text-sm text-slate-400">No students in this class yet.</p>
            ) : (
              <ul className="divide-y divide-slate-700/50">
                {students.map((s) => {
                  const guardians = guardiansByStudent.get(s.id) ?? [];
                  return (
                    <li key={s.id} className="py-2">
                      <p className="text-sm font-medium text-slate-200">{personName(s)}</p>
                      <p className="text-xs text-slate-500">
                        {guardians.length > 0 ? `Guardians: ${guardians.join(', ')}` : 'No guardian linked'}
                      </p>
                    </li>
                  );
                })}
              </ul>
            )}
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Staff</CardTitle>
          </CardHeader>
          <CardContent>
            {staff.length === 0 ? (
              <p className="text-sm text-slate-400">No staff assigned.</p>
            ) : (
              <ul className="space-y-1">
                {staff.map((m: AdminUserRow) => (
                  <li key={m.id} className="text-sm text-slate-200">
                    {personName(m)}
                    <span className="ml-2 text-xs text-slate-500">
                      {m.app_role?.name === 'teacher' ? 'Teacher' : 'Support'}
                    </span>
                  </li>
                ))}
              </ul>
            )}
          </CardContent>
        </Card>
      </div>

      <Card>
        <CardHeader>
          <CardTitle className="flex items-center gap-2 text-base">
            <ClipboardCheck size={16} />
            Daily attendance
          </CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          {canFill ? (
            <div className="space-y-4">
              <div className="max-w-xs space-y-1.5">
                <Label htmlFor="att-date">Date</Label>
                <input
                  id="att-date"
                  type="date"
                  value={date}
                  onChange={(e) => setDate(e.target.value)}
                  required
                  className="flex h-10 w-full rounded-md border border-border/60 bg-background px-3 py-2 text-sm text-slate-100 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
                />
              </div>

              <StudentAttendanceTable
                students={students}
                guardiansByStudent={guardiansByStudent}
                statuses={studentStatuses}
                onStatusChange={(studentId, nextStatus) => {
                  setStudentStatusOverrides((current) => ({ ...current, [studentId]: nextStatus }));
                  setStatus(null);
                }}
              />

              {status && (
                <div
                  className={`rounded-lg border px-3 py-2 text-sm ${
                    status.type === 'success'
                      ? 'border-emerald-500/30 bg-emerald-500/10 text-emerald-200'
                      : 'border-red-500/30 bg-red-500/10 text-red-200'
                  }`}
                >
                  {status.text}
                </div>
              )}

              <div className="flex justify-end">
                <Button type="button" onClick={handleAttendance} disabled={saving || students.length === 0}>
                  {saving && <Loader2 size={16} className="mr-2 animate-spin" />}
                  Save attendance
                </Button>
              </div>
            </div>
          ) : (
            <p className="text-sm text-slate-400">You have read-only access to attendance.</p>
          )}

          <div>
            <p className="mb-2 text-xs font-semibold text-slate-300">Recent</p>
            {(summaryQuery.data?.rows ?? []).length === 0 ? (
              <p className="text-sm text-slate-400">No attendance recorded yet.</p>
            ) : (
              <ul className="divide-y divide-slate-700/50">
                {(summaryQuery.data?.rows ?? []).slice(0, 7).map((row) => (
                  <li key={row.date} className="flex items-center justify-between py-1.5 text-sm">
                    <span className="text-slate-300">{row.date}</span>
                    <span className="text-slate-400">
                      {row.total_present}/{row.total_enrolled} present ({row.attendance_percentage}%)
                    </span>
                  </li>
                ))}
              </ul>
            )}
          </div>
        </CardContent>
      </Card>
    </div>
  );
}

function StudentAttendanceTable({
  students,
  guardiansByStudent,
  statuses,
  onStatusChange,
}: {
  students: readonly AdminUserRow[];
  guardiansByStudent: ReadonlyMap<string, readonly string[]>;
  statuses: Readonly<Record<string, StudentAttendanceStatus>>;
  onStatusChange: (studentId: string, status: StudentAttendanceStatus) => void;
}) {
  if (students.length === 0) {
    return (
      <div className="rounded-lg border border-slate-700/50 bg-slate-900/30 px-4 py-3 text-sm text-slate-400">
        No students in this class yet.
      </div>
    );
  }

  return (
    <div className="overflow-hidden rounded-lg border border-slate-700/60">
      <table className="w-full min-w-[640px] text-left text-sm">
        <thead className="bg-slate-900/70 text-xs uppercase text-slate-400">
          <tr>
            <th className="px-4 py-3 font-semibold">Student</th>
            {STUDENT_ATTENDANCE_STATUS_OPTIONS.map((option) => (
              <th key={option.value} className="w-28 px-4 py-3 text-center font-semibold">
                {option.label}
              </th>
            ))}
          </tr>
        </thead>
        <tbody className="divide-y divide-slate-800/80 bg-slate-950/20">
          {students.map((student) => {
            const currentStatus = statuses[student.id] ?? 'present';
            const guardians = guardiansByStudent.get(student.id) ?? [];
            return (
              <tr key={student.id}>
                <td className="px-4 py-3">
                  <p className="font-medium text-slate-200">{personName(student)}</p>
                  <p className="text-xs text-slate-500">
                    {guardians.length > 0 ? `Guardians: ${guardians.join(', ')}` : 'No guardian linked'}
                  </p>
                </td>
                {STUDENT_ATTENDANCE_STATUS_OPTIONS.map((option) => (
                  <td key={option.value} className="px-4 py-3 text-center">
                    <input
                      type="checkbox"
                      checked={currentStatus === option.value}
                      onChange={() => onStatusChange(student.id, option.value)}
                      aria-label={`${option.label} for ${personName(student)}`}
                      className="h-4 w-4 rounded border-slate-500 bg-slate-800 text-lime-500 focus:ring-lime-500"
                    />
                  </td>
                ))}
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}
