import { useCallback, useEffect, useRef, useState } from 'react' import { Box, Divider, Drawer, IconButton, TextField, Tooltip, Typography } from '@mui/material' import { RotateCcw, Send, Sparkles, X } from 'lucide-react' import { useLocation } from 'react-router' import { useAssistantStore } from '../../stores/assistantStore' import { useSessionStore } from '../../stores/sessionStore' import { aiAssistantService } from '../../services/aiAssistantService' import { AssistantContextSummary } from './AssistantContextSummary' import { AssistantMessageList } from './AssistantMessageList' import { AssistantPromptSuggestions } from './AssistantPromptSuggestions' import { AssistantLoadingState } from './AssistantLoadingState' import { AssistantErrorState } from './AssistantErrorState' import type { AssistantContext, SuggestedQuestion } from '../../domain/assistant' import type { WorkspaceType } from '../../domain/enums' function resolveWorkspace(pathname: string): WorkspaceType | null { if (pathname.startsWith('/supply')) return 'SUPPLY' as WorkspaceType if (pathname.startsWith('/demand')) return 'DEMAND' as WorkspaceType if (pathname.startsWith('/ops')) return 'OPERATIONS' as WorkspaceType return null } export function GlobalAIAssistantDrawer() { const { isOpen, close, context, setContext, messages, isLoading, error, addMessage, setLoading, setError, clearConversation } = useAssistantStore() const { currentUser } = useSessionStore() const location = useLocation() const [suggestions, setSuggestions] = useState([]) const [inputText, setInputText] = useState('') const scrollRef = useRef(null) // Build context from route when drawer opens useEffect(() => { if (!isOpen) return const ctx: AssistantContext = { currentRoute: location.pathname, workspace: resolveWorkspace(location.pathname), userRole: currentUser?.role ?? 'VIEWER', organizationId: currentUser?.organizationId ?? '', } setContext(ctx) aiAssistantService.getSuggestions(ctx).then(setSuggestions) }, [isOpen, location.pathname]) // Refresh suggestions when route changes while open useEffect(() => { if (!isOpen) return const ctx: AssistantContext = { currentRoute: location.pathname, workspace: resolveWorkspace(location.pathname), userRole: currentUser?.role ?? 'VIEWER', organizationId: currentUser?.organizationId ?? '', } setContext(ctx) aiAssistantService.getSuggestions(ctx).then(setSuggestions) }, [location.pathname]) // Auto-scroll on new messages useEffect(() => { if (scrollRef.current) { scrollRef.current.scrollTop = scrollRef.current.scrollHeight } }, [messages, isLoading]) const handleQuestion = useCallback(async (question: string) => { if (!question.trim() || isLoading) return setInputText('') setError(null) const userMsg = { id: crypto.randomUUID(), role: 'user' as const, content: question.trim(), createdAt: new Date().toISOString(), } addMessage(userMsg) setLoading(true) try { const ctx = context ?? { currentRoute: location.pathname, workspace: resolveWorkspace(location.pathname), userRole: currentUser?.role ?? 'VIEWER', organizationId: currentUser?.organizationId ?? '', } const answer = await aiAssistantService.answerQuestion(ctx, question) addMessage({ id: crypto.randomUUID(), role: 'assistant', createdAt: new Date().toISOString(), ...answer, }) } catch { setError('Antwort konnte nicht generiert werden. Bitte erneut versuchen.') } finally { setLoading(false) } }, [context, isLoading, location.pathname, currentUser, addMessage, setLoading, setError]) const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault() handleQuestion(inputText) } } const handleClear = () => { clearConversation() setSuggestions([]) if (context) { aiAssistantService.getSuggestions(context).then(setSuggestions) } } const showSuggestions = suggestions.length > 0 && messages.length === 0 return ( {/* Header */} AI Assistent Kontextbasierte Entscheidungsunterstützung {/* Context summary */} {context && } {/* Scrollable body */} {/* Welcome message */} {messages.length === 0 && !isLoading && ( Ich helfe Ihnen mit kontextbezogenen Fragen zu dieser Seite. Meine Antworten basieren auf strukturierten Daten — keine erfundenen Fakten. )} {/* Suggestions */} {showSuggestions && ( <> )} {/* Messages */} {messages.length > 0 && ( )} {/* Inline suggestions after messages */} {messages.length > 0 && suggestions.length > 0 && !isLoading && ( <> )} {/* Loading */} {isLoading && } {/* Error */} {error && setError(null)} />} {/* Input area */} setInputText(e.target.value)} onKeyDown={handleKeyDown} disabled={isLoading} sx={{ '& .MuiOutlinedInput-root': { fontSize: '0.8125rem', borderRadius: 2 }, }} /> handleQuestion(inputText)} disabled={!inputText.trim() || isLoading} sx={{ bgcolor: '#4f46e5', color: 'white', flexShrink: 0, '&:hover': { bgcolor: '#4338ca' }, '&:disabled': { bgcolor: '#e2e8f0', color: '#94a3b8' }, }} > Antworten sind datenbasiert — Aktionen erfordern manuelle Bestätigung ) }