'use client' import { useState, useEffect, useCallback, useRef } from 'react' import { FMScenario, FMResult, FMComputeResponse } from '../types' export function useFinancialModel() { const [scenarios, setScenarios] = useState([]) const [activeScenarioId, setActiveScenarioId] = useState(null) const [compareMode, setCompareMode] = useState(false) const [results, setResults] = useState>(new Map()) const [loading, setLoading] = useState(true) const [computing, setComputing] = useState(false) const computeTimer = useRef(null) // Load scenarios on mount useEffect(() => { async function load() { try { const res = await fetch('/api/financial-model') if (res.ok) { const data: FMScenario[] = await res.json() setScenarios(data) const defaultScenario = data.find(s => s.is_default) || data[0] if (defaultScenario) { setActiveScenarioId(defaultScenario.id) } } } catch (err) { console.error('Failed to load financial model:', err) } finally { setLoading(false) } } load() }, []) // Compute when active scenario changes useEffect(() => { if (activeScenarioId && !results.has(activeScenarioId)) { compute(activeScenarioId) } }, [activeScenarioId]) // eslint-disable-line react-hooks/exhaustive-deps const compute = useCallback(async (scenarioId: string) => { setComputing(true) try { const res = await fetch('/api/financial-model/compute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ scenarioId }), }) if (res.ok) { const data: FMComputeResponse = await res.json() setResults(prev => new Map(prev).set(scenarioId, data)) } } catch (err) { console.error('Compute failed:', err) } finally { setComputing(false) } }, []) const updateAssumption = useCallback(async (scenarioId: string, key: string, value: number | number[]) => { // Optimistic update in local state setScenarios(prev => prev.map(s => { if (s.id !== scenarioId) return s return { ...s, assumptions: s.assumptions.map(a => a.key === key ? { ...a, value } : a), } })) // Save to DB await fetch('/api/financial-model/assumptions', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ scenarioId, key, value }), }) // Debounced recompute if (computeTimer.current) clearTimeout(computeTimer.current) computeTimer.current = setTimeout(() => compute(scenarioId), 300) }, [compute]) const computeAll = useCallback(async () => { for (const s of scenarios) { await compute(s.id) } }, [scenarios, compute]) const activeScenario = scenarios.find(s => s.id === activeScenarioId) || null const activeResults = activeScenarioId ? results.get(activeScenarioId) || null : null return { scenarios, activeScenario, activeScenarioId, setActiveScenarioId, activeResults, results, loading, computing, compareMode, setCompareMode, compute, computeAll, updateAssumption, } }