'use client' import { useState, useEffect, useCallback } from 'react' import type { SeedURL, Category, CrawlStats } from './types' import { DEFAULT_CATEGORIES, DEFAULT_STATS, apiSeedToFrontend } from './types' export function useEduSearchData() { const [seeds, setSeeds] = useState([]) const [allSeeds, setAllSeeds] = useState([]) const [categories, setCategories] = useState(DEFAULT_CATEGORIES) const [stats, setStats] = useState(DEFAULT_STATS) const [selectedCategory, setSelectedCategory] = useState('all') const [loading, setLoading] = useState(false) const [initialLoading, setInitialLoading] = useState(true) const [error, setError] = useState(null) const fetchCategories = useCallback(async () => { try { const res = await fetch(`/api/admin/edu-search?action=categories`) if (res.ok) { const data = await res.json() if (data.categories && data.categories.length > 0) { setCategories(data.categories.map((cat: { id: string; name: string; display_name: string; description: string; icon: string; sort_order: number; is_active: boolean }) => ({ id: cat.id, name: cat.name, display_name: cat.display_name, description: cat.description || '', icon: cat.icon || '📁', sort_order: cat.sort_order, is_active: cat.is_active, }))) } } } catch (err) { console.error('Failed to fetch categories:', err) } }, []) const fetchAllSeeds = useCallback(async () => { try { const res = await fetch(`/api/admin/edu-search?action=seeds`) if (!res.ok) throw new Error(`HTTP ${res.status}`) const data = await res.json() setAllSeeds((data.seeds || []).map(apiSeedToFrontend)) } catch (err) { console.error('Failed to fetch all seeds:', err) } }, []) const fetchSeeds = useCallback(async () => { try { const params = new URLSearchParams() params.append('action', 'seeds') if (selectedCategory !== 'all') params.append('category', selectedCategory) const res = await fetch(`/api/admin/edu-search?${params}`) if (!res.ok) throw new Error(`HTTP ${res.status}`) const data = await res.json() const fetchedSeeds = (data.seeds || []).map(apiSeedToFrontend) setSeeds(fetchedSeeds) if (selectedCategory === 'all') setAllSeeds(fetchedSeeds) setError(null) } catch (err) { console.error('Failed to fetch seeds:', err) setError('Seeds konnten nicht geladen werden. API nicht erreichbar.') } }, [selectedCategory]) const fetchStats = useCallback(async (preserveCrawlStatus = false) => { try { const res = await fetch(`/api/admin/edu-search?action=stats`) if (res.ok) { const data = await res.json() setStats(prev => ({ totalDocuments: data.total_documents || 0, totalSeeds: data.total_seeds || 0, lastCrawlTime: data.last_crawl_time || prev.lastCrawlTime, crawlStatus: preserveCrawlStatus ? prev.crawlStatus : (data.crawl_status || 'idle'), documentsPerCategory: data.seeds_per_category || {}, documentsPerDocType: {}, avgTrustScore: data.avg_trust_boost || 0, })) } } catch (err) { console.error('Failed to fetch stats:', err) } }, []) useEffect(() => { const loadData = async () => { setInitialLoading(true) await Promise.all([fetchCategories(), fetchSeeds(), fetchAllSeeds(), fetchStats()]) setInitialLoading(false) } loadData() }, [fetchCategories, fetchSeeds, fetchAllSeeds, fetchStats]) useEffect(() => { if (!initialLoading) fetchSeeds() }, [selectedCategory, initialLoading, fetchSeeds]) const pollCrawlStatus = useCallback(async () => { try { const res = await fetch('/api/admin/edu-search?action=legal-crawler-status', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }) if (res.ok) return (await res.json()).status } catch { /* Ignore */ } return 'idle' }, []) const handleStartCrawl = async () => { setLoading(true) setError(null) setStats(prev => ({ ...prev, crawlStatus: 'running', lastCrawlTime: new Date().toISOString() })) try { const response = await fetch('/api/admin/edu-search?action=crawl', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}), }) const data = await response.json() if (response.ok) { const checkStatus = async () => { const status = await pollCrawlStatus() if (status === 'running') { setStats(prev => ({ ...prev, crawlStatus: 'running' })); setTimeout(checkStatus, 3000) } else if (status === 'completed' || status === 'idle') { setStats(prev => ({ ...prev, crawlStatus: 'idle' })); setLoading(false); await fetchStats(false) } else { setStats(prev => ({ ...prev, crawlStatus: 'error' })); setLoading(false) } } setTimeout(checkStatus, 2000) } else { setError(data.error || 'Fehler beim Starten des Crawls') setLoading(false) setStats(prev => ({ ...prev, crawlStatus: 'idle' })) } } catch (err) { setError('Netzwerkfehler beim Starten des Crawls') setLoading(false) setStats(prev => ({ ...prev, crawlStatus: 'idle' })) } } const handleDelete = async (id: string) => { if (!confirm('Seed-URL wirklich löschen?')) return try { const res = await fetch(`/api/admin/edu-search?id=${id}`, { method: 'DELETE' }) if (!res.ok) throw new Error(`HTTP ${res.status}`) await fetchSeeds(); await fetchStats() } catch (err) { console.error('Failed to delete seed:', err) alert('Fehler beim Löschen') } } const handleToggleEnabled = async (id: string) => { const seed = seeds.find(s => s.id === id) if (!seed) return try { const res = await fetch(`/api/admin/edu-search?id=${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: !seed.enabled }), }) if (!res.ok) throw new Error(`HTTP ${res.status}`) setSeeds(seeds.map(s => s.id === id ? { ...s, enabled: !s.enabled } : s)) } catch (err) { console.error('Failed to toggle seed:', err); await fetchSeeds() } } const handleSaved = async () => { await fetchSeeds(); await fetchStats() } return { seeds, allSeeds, categories, stats, selectedCategory, setSelectedCategory, loading, initialLoading, error, setError, handleStartCrawl, handleDelete, handleToggleEnabled, handleSaved, fetchSeeds, fetchStats, } }