import { createContext, useContext, useEffect, useMemo, useState } from 'react' import type { ReactNode } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import type { SessionStudents } from '@gruperly/shared' import { useToast } from '../../components/ui' import { getSessionStudents, markAttendance } from '../../lib/api' import { isAttendanceLocked } from './utils' import type { AttendanceChoice } from './utils' type AttendanceContextValue = { sessionId: string sessionInfo: SessionStudents | undefined studentsPending: boolean studentsFailed: boolean retryStudents: () => void startTime: string | null presentCount: number choices: Record choiceFor: (attendeeId: string) => AttendanceChoice toggleStudent: (attendeeId: string) => void saveAttendance: () => void isSaving: boolean } const AttendanceContext = createContext(null) export function AttendanceProvider({ sessionId, children }: { sessionId: string; children: ReactNode }) { const queryClient = useQueryClient() const toast = useToast() const studentsQuery = useQuery({ queryKey: ['class-students', sessionId], queryFn: () => getSessionStudents(sessionId), staleTime: 0, }) const sessionInfo = studentsQuery.data const [choices, setChoices] = useState>({}) useEffect(() => { if (!sessionInfo) return const initial: Record = {} for (const student of sessionInfo.students) { if (isAttendanceLocked(student)) continue initial[student.attendeeId] = student.attendanceStatus === 'ABSENT' ? 'ABSENT' : 'PRESENT' } setChoices(initial) }, [sessionInfo]) const presentCount = useMemo( () => (sessionInfo?.students ?? []).filter( (student) => !isAttendanceLocked(student) && choices[student.attendeeId] === 'PRESENT', ).length, [sessionInfo, choices], ) const toggleStudent = (attendeeId: string) => { setChoices((prev) => ({ ...prev, [attendeeId]: prev[attendeeId] === 'ABSENT' ? 'PRESENT' : 'ABSENT', })) } const saveMutation = useMutation({ mutationFn: () => { const records = (sessionInfo?.students ?? []) .filter((student) => !isAttendanceLocked(student)) .map((student) => ({ attendeeId: student.attendeeId, status: choices[student.attendeeId] ?? 'PRESENT', })) return markAttendance(sessionId, { classSessionId: sessionId, records }) }, onSuccess: () => { toast.success('Asistencia guardada correctamente.', 'Listo') void queryClient.invalidateQueries({ queryKey: ['classes-today'] }) void queryClient.invalidateQueries({ queryKey: ['class-students', sessionId] }) }, onError: (error: Error) => { toast.error(error.message || 'No pudimos guardar la asistencia.') }, }) const startTime = sessionInfo ? new Date(sessionInfo.startsAt).toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit', hour12: false, }) : null const value: AttendanceContextValue = { sessionId, sessionInfo, studentsPending: studentsQuery.isPending, studentsFailed: studentsQuery.isError, retryStudents: () => void studentsQuery.refetch(), startTime, presentCount, choices, choiceFor: (attendeeId) => choices[attendeeId] ?? 'PRESENT', toggleStudent, saveAttendance: () => saveMutation.mutate(), isSaving: saveMutation.isPending, } return {children} } export function useAttendance() { const context = useContext(AttendanceContext) if (!context) { throw new Error('useAttendance debe usarse dentro de ') } return context }