import { createContext, useContext, useState, useCallback, useMemo, useRef, useEffect, type ReactNode } from 'react' import { toast } from 'sonner' import { jobApi } from '@/lib/api' import type { Job, JobStatus } from '@/types/job' import { POLL_INTERVAL } from '@/lib/constants' import { useHistoryContext } from '@/contexts/HistoryContext' interface JobContextType { currentJob: Job | null status: JobStatus | null error: string | null elapsedTime: number startJob: (jobId: number) => void stopJob: () => void resetJob: () => void loadCompletedJob: (job: Job) => void } const JobContext = createContext(undefined) export function JobProvider({ children }: { children: ReactNode }) { const [currentJob, setCurrentJob] = useState(null) const [status, setStatus] = useState(null) const [error, setError] = useState(null) const [elapsedTime, setElapsedTime] = useState(0) const { refresh: historyRefresh } = useHistoryContext() const pollIntervalRef = useRef | null>(null) const timeIntervalRef = useRef | null>(null) const clearIntervals = useCallback(() => { if (pollIntervalRef.current) { clearInterval(pollIntervalRef.current) pollIntervalRef.current = null } if (timeIntervalRef.current) { clearInterval(timeIntervalRef.current) timeIntervalRef.current = null } }, []) const stopJob = useCallback(() => { clearIntervals() setCurrentJob(null) setStatus(null) setError(null) setElapsedTime(0) }, [clearIntervals]) const resetJob = useCallback(() => { setError(null) }, []) const loadCompletedJob = useCallback((job: Job) => { setCurrentJob(job) setStatus(job.status) setError(job.error_message || null) setElapsedTime(0) }, []) const startJob = useCallback((jobId: number) => { clearIntervals() // Reset state for new job setCurrentJob(null) setStatus('pending') setError(null) setElapsedTime(0) const poll = async () => { try { const job = await jobApi.getJob(jobId) setCurrentJob(job) setStatus(job.status) if (job.status === 'completed') { clearIntervals() toast.success('任务完成!') try { historyRefresh() } catch {} } else if (job.status === 'failed') { clearIntervals() setError(job.error_message || '任务失败') toast.error(job.error_message || '任务失败') try { historyRefresh() } catch {} } } catch (error: any) { clearIntervals() const message = error.response?.data?.detail || '获取任务状态失败' setError(message) toast.error(message) } } poll() pollIntervalRef.current = setInterval(poll, POLL_INTERVAL) timeIntervalRef.current = setInterval(() => { setElapsedTime((prev) => prev + 1) }, 1000) }, [historyRefresh, clearIntervals]) useEffect(() => { return () => { clearIntervals() } }, [clearIntervals]) const value = useMemo( () => ({ currentJob, status, error, elapsedTime, startJob, stopJob, resetJob, loadCompletedJob, }), [currentJob, status, error, elapsedTime, startJob, stopJob, resetJob, loadCompletedJob] ) return ( {children} ) } export function useJob() { const context = useContext(JobContext) if (!context) { throw new Error('useJob must be used within JobProvider') } return context }