'use client'

import { useState, useEffect, useCallback, useRef } from 'react'
import { FMScenario, FMResult, FMComputeResponse, InvestorSnapshot } from '../types'

export function useFinancialModel(investorId?: string | null, preferredScenarioId?: string | null) {
  const [scenarios, setScenarios] = useState<FMScenario[]>([])
  const [activeScenarioId, setActiveScenarioId] = useState<string | null>(null)
  const [compareMode, setCompareMode] = useState(false)
  const [results, setResults] = useState<Map<string, FMComputeResponse>>(new Map())
  const [loading, setLoading] = useState(true)
  const [computing, setComputing] = useState(false)
  const [snapshotStatus, setSnapshotStatus] = useState<'default' | 'saving' | 'saved' | 'restored'>('default')
  const computeTimer = useRef<NodeJS.Timeout | null>(null)
  const snapshotTimer = useRef<NodeJS.Timeout | null>(null)
  const snapshotsLoaded = useRef(false)

  // Load scenarios on mount, then apply snapshots if investor is logged in
  useEffect(() => {
    async function load() {
      try {
        const res = await fetch('/api/financial-model')
        if (res.ok) {
          let data: FMScenario[] = await res.json()

          // If investor is logged in, restore their snapshots
          if (investorId && !snapshotsLoaded.current) {
            try {
              const snapRes = await fetch('/api/snapshots')
              if (snapRes.ok) {
                const { snapshots } = await snapRes.json() as { snapshots: InvestorSnapshot[] }
                if (snapshots.length > 0) {
                  data = data.map(scenario => {
                    const snapshot = snapshots.find(s => s.scenario_id === scenario.id)
                    if (!snapshot) return scenario
                    return {
                      ...scenario,
                      assumptions: scenario.assumptions.map(a => {
                        const savedValue = snapshot.assumptions[a.key]
                        return savedValue !== undefined ? { ...a, value: savedValue } : a
                      }),
                    }
                  })
                  setSnapshotStatus('restored')
                }
              }
            } catch {
              // Snapshot restore failed — use defaults
            }
            snapshotsLoaded.current = true
          }

          setScenarios(data)
          // Use preferred scenario if available, otherwise default
          const preferred = preferredScenarioId ? data.find(s => s.id === preferredScenarioId) : null
          const defaultScenario = preferred || 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()
  }, [investorId])

  // 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)
    }
  }, [])

  // Auto-save snapshot (debounced)
  const saveSnapshot = useCallback(async (scenarioId: string) => {
    if (!investorId) return
    const scenario = scenarios.find(s => s.id === scenarioId)
    if (!scenario) return

    const assumptions: Record<string, number | number[]> = {}
    scenario.assumptions.forEach(a => { assumptions[a.key] = a.value })

    setSnapshotStatus('saving')
    try {
      await fetch('/api/snapshots', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ scenario_id: scenarioId, assumptions }),
      })
      setSnapshotStatus('saved')
    } catch {
      setSnapshotStatus('default')
    }
  }, [investorId, scenarios])

  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)

    // Debounced snapshot save (2s after last change)
    if (snapshotTimer.current) clearTimeout(snapshotTimer.current)
    snapshotTimer.current = setTimeout(() => saveSnapshot(scenarioId), 2000)
  }, [compute, saveSnapshot])

  const resetToDefaults = useCallback(async (scenarioId: string) => {
    // Reload from server (without snapshots)
    try {
      const res = await fetch('/api/financial-model')
      if (res.ok) {
        const data: FMScenario[] = await res.json()
        const defaultScenario = data.find(s => s.id === scenarioId)
        if (defaultScenario) {
          setScenarios(prev => prev.map(s => s.id === scenarioId ? defaultScenario : s))
          // Delete snapshot
          if (investorId) {
            await fetch(`/api/snapshots?id=${scenarioId}`, { method: 'DELETE' })
          }
          setSnapshotStatus('default')
          compute(scenarioId)
        }
      }
    } catch {
      // ignore
    }
  }, [compute, investorId])

  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,
    resetToDefaults,
    snapshotStatus,
  }
}
