import React, { createContext, useContext, useEffect, useRef, useState, useCallback, } from "react"; import { getAutoComplete, AutoCompleteItem } from "@/apis/autoCompleteApi"; type DiscoveryContextType = { query: string; setQuery: (q: string) => void; suggestions: AutoCompleteItem[]; loading: boolean; error: string | null; clear: () => void; }; const DiscoveryContext = createContext(null); export const DiscoveryProvider = ({ children, }: { children: React.ReactNode; }) => { const [query, setQuery] = useState(""); const [suggestions, setSuggestions] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const abortRef = useRef(null); const debounceRef = useRef | null>(null); const cacheRef = useRef>({}); const fetchSuggestions = useCallback((q: string) => { if (abortRef.current) abortRef.current.abort(); if (!q.trim()) { setSuggestions([]); setLoading(false); return; } const cached = cacheRef.current[q]; if (cached) { setSuggestions(cached); setLoading(false); return; } const controller = new AbortController(); abortRef.current = controller; setLoading(true); setError(null); getAutoComplete(q, 10, controller.signal) .then((items) => { cacheRef.current[q] = items; setSuggestions(items); }) .catch((e) => { if (controller.signal.aborted) return; setError(e.message || "Fehler"); }) .finally(() => { if (!controller.signal.aborted) setLoading(false); }); }, []); useEffect(() => { if (debounceRef.current) clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => fetchSuggestions(query), 300); return () => { if (debounceRef.current) clearTimeout(debounceRef.current); }; }, [query, fetchSuggestions]); const clear = () => { setQuery(""); setSuggestions([]); setError(null); }; return ( {children} ); }; export const useDiscoveryContext = () => { const ctx = useContext(DiscoveryContext); if (!ctx) throw new Error( "useDiscoveryContext must be used within DiscoveryProvider" ); return ctx; };