"use client"; import { useState, useCallback, useRef, useEffect } from "react"; import { v4 as uuidv4 } from "uuid"; import { Message, ChatResponse, EmailActionOptions } from "@/types/chat"; export function useChat() { const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [preferredModel, setPreferredModel] = useState("llama-3.1-8b-instant"); const sessionId = useRef(uuidv4()); useEffect(() => { if (typeof window !== "undefined") { const saved = localStorage.getItem("preferred_model"); if (saved) { setPreferredModel(saved); } } }, []); const selectModel = useCallback((model: string) => { setPreferredModel(model); if (typeof window !== "undefined") { localStorage.setItem("preferred_model", model); } }, []); const sendMessage = useCallback(async (content: string, options?: EmailActionOptions) => { const trimmed = content.trim(); // Allow action-only turns (e.g. Send/Cancel buttons) even with empty text. if ((!trimmed && !options?.emailAction) || isLoading) return; const display = options?.displayContent ?? trimmed; const userMsg: Message = { id: uuidv4(), role: "user", content: display, timestamp: new Date(), }; setMessages((prev) => [...prev, userMsg]); setIsLoading(true); setError(null); try { const res = await fetch("/api/chat", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: sessionId.current, message: trimmed || display, model: preferredModel, email_action: options?.emailAction, email_payload: options?.emailPayload, }), }); if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.detail ?? `Server error ${res.status}`); } const data: ChatResponse = await res.json(); const assistantMsg: Message = { id: uuidv4(), role: "assistant", content: data.answer, sources: data.sources, timestamp: new Date(), responseType: data.response_type, structuredData: data.structured_data, tokenUsage: data.token_usage, modelUsed: data.model_used, rateLimit: data.rate_limit, }; setMessages((prev) => [...prev, assistantMsg]); } catch (err) { const message = err instanceof Error ? err.message : "An unexpected error occurred"; setError(message); } finally { setIsLoading(false); } }, [isLoading, preferredModel]); const clearConversation = useCallback(async () => { const sid = sessionId.current; sessionId.current = uuidv4(); setMessages([]); setError(null); await fetch(`/api/chat/${sid}`, { method: "DELETE" }).catch(() => null); }, []); return { messages, isLoading, error, sendMessage, clearConversation, hasMessages: messages.length > 0, preferredModel, setPreferredModel: selectModel, }; }