import { useState } from 'react' import { qaApi } from '../services/api' import type { JobRead, QaComparisonRequest, QaComparisonResult, QualityCheckRead, QualityEvidenceGeoJsonResponse } from '../types' import { formatError } from '../lib/formatError' interface QualityWorkflowOptions { selectedProjectId: string | null loadProjectData: (projectId: string) => Promise } export function useQualityWorkflow({ selectedProjectId, loadProjectData }: QualityWorkflowOptions) { const [qaCandidateDatasetId, setQaCandidateDatasetId] = useState('') const [qaReferenceDatasetId, setQaReferenceDatasetId] = useState('') const [qaAreaId, setQaAreaId] = useState('') const [qaIouThreshold, setQaIouThreshold] = useState(0.5) const [qaRunning, setQaRunning] = useState(false) const [qaResult, setQaResult] = useState(null) const [qaError, setQaError] = useState(null) const [qualityChecks, setQualityChecks] = useState([]) const [qualityChecksError, setQualityChecksError] = useState(null) const [qualityEvidenceGeoJson, setQualityEvidenceGeoJson] = useState(null) const [qualityEvidenceLoading, setQualityEvidenceLoading] = useState(false) const [qualityEvidenceError, setQualityEvidenceError] = useState(null) const loadQualityChecks = async (projectId = selectedProjectId): Promise => { if (!projectId) { setQualityChecks([]) return [] } setQualityChecksError(null) try { const response = await qaApi.listQualityChecks(projectId) setQualityChecks(response.items) return response.items } catch (error) { setQualityChecksError(formatError(error, 'Failed to load QA/QC results')) } } const loadQualityEvidenceGeoJson = async (qualityCheckId: string, projectId = selectedProjectId): Promise => { if (!projectId) { setQualityEvidenceError('Select a project first') return null } setQualityEvidenceLoading(true) setQualityEvidenceError(null) try { const response = await qaApi.getQualityEvidenceGeoJson(projectId, qualityCheckId) setQualityEvidenceGeoJson(response) return response } catch (error) { setQualityEvidenceError(formatError(error, 'Failed to load QA/QC evidence overlay')) return null } finally { setQualityEvidenceLoading(false) } } const clearQualityEvidenceGeoJson = () => { setQualityEvidenceGeoJson(null) setQualityEvidenceError(null) } const runQaComparison = async () => { if (!selectedProjectId) { setQaError('Select a project first') return } if (!qaCandidateDatasetId) { setQaError('Select candidate dataset') return } if (!qaReferenceDatasetId) { setQaError('Select reference dataset') return } if (qaCandidateDatasetId === qaReferenceDatasetId) { setQaError('Candidate and reference datasets must be different') return } if (!Number.isFinite(qaIouThreshold) || qaIouThreshold < 0 || qaIouThreshold > 1) { setQaError('IoU threshold must be between 0 and 1') return } setQaError(null) setQaResult(null) setQaRunning(true) try { const request: QaComparisonRequest = { candidate_dataset_id: qaCandidateDatasetId, reference_dataset_id: qaReferenceDatasetId, iou_threshold: qaIouThreshold, area_id: qaAreaId || null, } const job: JobRead = await qaApi.runQa(request) if (job.status === 'failed') { setQaError(job.error_message || 'QA comparison failed') return } const payload = job.result_json if (!payload || typeof payload !== 'object') { setQaError('QA result was not available') return } const parsed = payload as unknown as QaComparisonResult if (!parsed || typeof parsed.status !== 'string') { setQaError('QA result format was unexpected') return } setQaResult(parsed) await loadQualityChecks(selectedProjectId) if (job.output_dataset_id) { await loadProjectData(selectedProjectId) } } catch (error) { setQaError(error instanceof Error ? error.message : 'QA comparison failed') } finally { setQaRunning(false) } } return { qaCandidateDatasetId, qaReferenceDatasetId, qaAreaId, qaIouThreshold, qaRunning, qaResult, qaError, qualityChecks, qualityChecksError, qualityEvidenceGeoJson, qualityEvidenceLoading, qualityEvidenceError, loadQualityChecks, loadQualityEvidenceGeoJson, clearQualityEvidenceGeoJson, runQaComparison, setQaCandidateDatasetId, setQaReferenceDatasetId, setQaAreaId, setQaIouThreshold, } }