import { useState, useCallback, useContext, createContext, type ReactNode } from 'react'; import type { AnalysisResult, FilterParams, JobStatus } from '../types'; import { api } from '../services/api'; interface AnalysisState { jobs: JobStatus[]; currentResult: AnalysisResult | null; activeJobId: string | null; loading: boolean; error: string | null; uploadFile: (file: File, source?: string) => Promise; loadJobs: () => Promise; loadResult: (jobId: string) => Promise; selectJob: (jobId: string) => void; pollJobStatus: (jobId: string, onUpdate?: (status: JobStatus) => void) => Promise; exportResults: (jobId: string, format: 'csv' | 'json' | 'pdf', filters?: FilterParams) => Promise; setError: (error: string | null) => void; } const AnalysisContext = createContext(null); export function AnalysisProvider({ children }: { children: ReactNode }) { const [jobs, setJobs] = useState([]); const [currentResult, setCurrentResult] = useState(null); const [activeJobId, setActiveJobId] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const uploadFile = useCallback(async (file: File, source?: string) => { setLoading(true); setError(null); try { const useChunked = file.size > 10 * 1024 * 1024; const status = useChunked ? await api.uploadChunked(file) : await api.uploadFile(file, source); setJobs((prev) => [status, ...prev]); return status; } catch (err) { const msg = err instanceof Error ? err.message : 'Upload failed'; setError(msg); throw err; } finally { setLoading(false); } }, []); const loadJobs = useCallback(async () => { try { const data = await api.getJobs(); setJobs(data); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load jobs'); } }, []); const loadResult = useCallback(async (jobId: string) => { setLoading(true); setError(null); try { const result = await api.getJobResult(jobId); setCurrentResult(result); setActiveJobId(jobId); return result; } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load results'); throw err; } finally { setLoading(false); } }, []); const selectJob = useCallback((jobId: string) => { setActiveJobId(jobId); loadResult(jobId); }, [loadResult]); const pollJobStatus = useCallback( async (jobId: string, onUpdate?: (status: JobStatus) => void) => { const poll = async () => { try { const status = await api.getJobStatus(jobId); onUpdate?.(status); if (status.status === 'completed') { await loadResult(jobId); return; } if (status.status === 'failed') { setError('Analysis failed'); return; } setTimeout(poll, 2000); } catch { setTimeout(poll, 5000); } }; poll(); }, [loadResult], ); const exportResults = useCallback(async (jobId: string, format: 'csv' | 'json' | 'pdf', filters?: FilterParams) => { try { const blob = await api.exportResults(jobId, format, filters); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `analysis_${jobId}.${format}`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } catch (err) { setError(err instanceof Error ? err.message : 'Export failed'); } }, []); return ( {children} ); } export function useAnalysis(): AnalysisState { const context = useContext(AnalysisContext); if (!context) { throw new Error('useAnalysis must be used within an AnalysisProvider'); } return context; }