import { AUTH_TOKEN_KEY } from './authClient'; const getAuthHeaders = () => { const token = localStorage.getItem(AUTH_TOKEN_KEY); return { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) }; }; function apiUrl(path: string): string { const base = ( import.meta.env.VITE_API_BASE as string | undefined ) ?.trim() .replace(/\/$/, '') ?? ''; const p = path.startsWith('/') ? path : `/${path}`; return `${base}${p}`; } export interface AIThread { id: string; userId: string; title: string; createdAt: string; updatedAt: string; } export interface AIMessage { id: string; threadId: string; role: 'user' | 'assistant' | 'system'; content: string; createdAt: string; } export type AITeacherMode = 'learning' | 'placement' | 'files'; export async function fetchThreads(): Promise { const res = await fetch(apiUrl('/api/ai/threads'), { headers: getAuthHeaders() }); if (!res.ok) throw new Error('Failed to fetch threads'); const data = await res.json(); return data.threads; } export async function createThread(title: string): Promise { const res = await fetch(apiUrl('/api/ai/threads/new'), { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ title }) }); if (!res.ok) throw new Error('Failed to create thread'); const data = await res.json(); return data.thread; } export async function fetchThreadMessages(threadId: string): Promise { const res = await fetch(apiUrl(`/api/ai/threads/messages?threadId=${threadId}`), { headers: getAuthHeaders() }); if (!res.ok) throw new Error('Failed to fetch messages'); const data = await res.json(); return data.messages; } export async function deleteThread(threadId: string): Promise { const res = await fetch(apiUrl(`/api/ai/threads/delete?threadId=${threadId}`), { method: 'DELETE', headers: getAuthHeaders() }); if (!res.ok) throw new Error('Failed to delete thread'); } export interface AIFileAttachment { name: string; type: string; size: number; kind: string; textExcerpt: string; } export interface AIChatResponse { thread?: AIThread; userMessage: AIMessage; assistantMessage: AIMessage; message: AIMessage; } export async function sendMessageToThread( threadId: string, message: string, attachments?: AIFileAttachment[], mode?: AITeacherMode, ): Promise { const res = await fetch(apiUrl('/api/ai/teacher'), { method: 'POST', headers: getAuthHeaders(), body: JSON.stringify({ threadId, message, attachments: attachments || [], mode: mode || 'learning', }) }); if (!res.ok) { let errorMessage = 'Failed to send message'; try { const data = await res.json(); if (typeof data?.error === 'string' && data.error.trim()) { errorMessage = data.error.trim(); } } catch { // Ignore JSON parsing errors and use fallback text. } throw new Error(errorMessage); } const data = await res.json(); return { thread: data.thread, userMessage: data.userMessage, assistantMessage: data.assistantMessage || data.message, message: data.message, }; }