import { useQueryClient } from '@tanstack/react-query' import { useParams } from '@tanstack/react-router' import { Sparkles, Send, Target, UserCheck, Lightbulb, FileText, GraduationCap, BookOpen, Check, X, MessageSquarePlus, Archive, History, // Agregado } from 'lucide-react' import { useState, useEffect, useRef, useMemo } from 'react' import type { IASugerencia } from '@/types/asignatura' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Button } from '@/components/ui/button' import { ScrollArea } from '@/components/ui/scroll-area' import { Textarea } from '@/components/ui/textarea' import { useAISubjectChat, useConversationBySubject, useMessagesBySubjectChat, useSubject, useUpdateSubjectConversationStatus, } from '@/data' import { cn } from '@/lib/utils' interface SelectedField { key: string label: string value: string } interface IAAsignaturaTabProps { asignatura?: Record onAcceptSuggestion: (sugerencia: IASugerencia) => void onRejectSuggestion: (messageId: string) => void } export function IAAsignaturaTab({ onAcceptSuggestion, onRejectSuggestion, }: IAAsignaturaTabProps) { const queryClient = useQueryClient() const { asignaturaId } = useParams({ from: '/planes/$planId/asignaturas/$asignaturaId', }) // --- ESTADOS --- const [activeChatId, setActiveChatId] = useState( undefined, ) const [showArchived, setShowArchived] = useState(false) const [input, setInput] = useState('') const [selectedFields, setSelectedFields] = useState>([]) const [showSuggestions, setShowSuggestions] = useState(false) const [isSending, setIsSending] = useState(false) const scrollRef = useRef(null) // --- DATA QUERIES --- const { data: datosGenerales } = useSubject(asignaturaId) const { data: todasConversaciones, isLoading: loadingConv } = useConversationBySubject(asignaturaId) const { data: rawMessages } = useMessagesBySubjectChat(activeChatId, { enabled: !!activeChatId, }) const { mutateAsync: sendMessage } = useAISubjectChat() const { mutate: updateStatus } = useUpdateSubjectConversationStatus() const [isCreatingNewChat, setIsCreatingNewChat] = useState(false) const hasInitialSelected = useRef(false) // --- AUTO-SCROLL --- useEffect(() => { const viewport = scrollRef.current?.querySelector( '[data-radix-scroll-area-viewport]', ) if (viewport) { viewport.scrollTop = viewport.scrollHeight } }, [rawMessages, isSending]) // --- FILTRADO DE CHATS --- const { activeChats, archivedChats } = useMemo(() => { const chats = todasConversaciones || [] return { activeChats: chats.filter((c: any) => c.estado === 'ACTIVA'), archivedChats: chats.filter((c: any) => c.estado === 'ARCHIVADA'), } }, [todasConversaciones]) // --- PROCESAMIENTO DE MENSAJES --- const messages = useMemo(() => { if (!rawMessages) return [] return rawMessages.flatMap((m) => { const msgs = [] msgs.push({ id: `${m.id}-user`, role: 'user', content: m.mensaje }) if (m.respuesta) { msgs.push({ id: `${m.id}-ai`, role: 'assistant', content: m.respuesta, sugerencia: m.propuesta?.recommendations?.[0] ? { id: m.id, campoKey: m.propuesta.recommendations[0].campo_afectado, campoNombre: m.propuesta.recommendations[0].campo_afectado.replace( /_/g, ' ', ), valorSugerido: m.propuesta.recommendations[0].texto_mejora, aceptada: m.propuesta.recommendations[0].aplicada, } : null, }) } return msgs }) }, [rawMessages]) // Auto-selección inicial useEffect(() => { // Si ya hay un chat, o si el usuario ya interactuó (hasInitialSelected), abortamos. if (activeChatId || hasInitialSelected.current) return if (activeChats.length > 0 && !loadingConv) { setActiveChatId(activeChats[0].id) hasInitialSelected.current = true } }, [activeChats, loadingConv]) const handleSend = async (promptOverride?: string) => { const text = promptOverride || input if (!text.trim() && selectedFields.length === 0) return setIsSending(true) try { const response = await sendMessage({ subjectId: asignaturaId as any, // Importante: se usa para crear la conv si activeChatId es undefined content: text, campos: selectedFields.map((f) => f.key), conversacionId: activeChatId, // Si es undefined, la mutación crea el chat automáticamente }) // IMPORTANTE: Después de la respuesta, actualizamos el ID activo con el que creó el backend if (response.conversacionId) { setActiveChatId(response.conversacionId) } setInput('') setSelectedFields([]) // Invalidamos la lista de conversaciones para que el nuevo chat aparezca en el historial (panel izquierdo) queryClient.invalidateQueries({ queryKey: ['conversation-by-subject', asignaturaId], }) } catch (error) { console.error('Error al enviar mensaje:', error) } finally { setIsSending(false) } } const toggleField = (field: SelectedField) => { setSelectedFields((prev) => prev.find((f) => f.key === field.key) ? prev.filter((f) => f.key !== field.key) : [...prev, field], ) } const availableFields = useMemo(() => { if (!datosGenerales?.datos) return [] const estructuraProps = datosGenerales?.estructuras_asignatura?.definicion?.properties || {} return Object.keys(datosGenerales.datos).map((key) => ({ key, label: estructuraProps[key]?.title || key.replace(/_/g, ' ').toUpperCase(), value: String(datosGenerales.datos[key] || ''), })) }, [datosGenerales]) const createNewChat = () => { setActiveChatId(undefined) // Al ser undefined, el próximo mensaje creará la charla en el backend setInput('') setSelectedFields([]) // Opcional: podrías forzar el foco al textarea aquí con una ref } const PRESETS = [ { id: 'mejorar-obj', label: 'Mejorar objetivo', icon: Target, prompt: 'Mejora la redacción del objetivo...', }, { id: 'sugerir-cont', label: 'Sugerir contenido', icon: BookOpen, prompt: 'Genera un desglose de temas...', }, { id: 'actividades', label: 'Actividades', icon: GraduationCap, prompt: 'Sugiere actividades prácticas...', }, ] return (
{/* PANEL IZQUIERDO */}

Historial

{(showArchived ? archivedChats : activeChats).map((chat: any) => (
{ setActiveChatId(chat.id) setIsCreatingNewChat(false) // <--- Volvemos al modo normal }} className={cn( 'group relative flex cursor-pointer items-center gap-3 rounded-lg px-3 py-2 text-sm transition-all', activeChatId === chat.id ? 'bg-teal-50 font-medium text-teal-900' : 'text-slate-600 hover:bg-slate-100', )} > {chat.titulo || 'Conversación'}
))}
{/* PANEL CENTRAL */}
Asistente IA
{messages.length === 0 && !isSending && (

Nueva Consultoría IA

Selecciona campos con ":" o usa una acción rápida para comenzar.

)} {messages.map((msg) => (
{msg.role === 'assistant' ? ( ) : ( )}
{msg.content}
{msg.sugerencia && !msg.sugerencia.aceptada && (

Propuesta: {msg.sugerencia.campoNombre}

{msg.sugerencia.valorSugerido}
)}
))} {isSending && (
)}
{/* INPUT */}
{showSuggestions && (
Campos de Asignatura
{availableFields.map((field) => ( ))}
)}
{selectedFields.length > 0 && (
{selectedFields.map((field) => (
{field.label}
))}
)}