/**
 * React hook that manages communication with the calcpad WASM engine
 * running in a Web Worker. Provides a function to evaluate a sheet
 * (array of lines) and returns results asynchronously.
 */

import { useRef, useEffect, useCallback, useState } from 'react'
import type { WorkerResponse, EngineLineResult } from './types.ts'

export interface EngineState {
  /** Whether the worker is initialized and ready */
  ready: boolean
  /** Evaluate a full sheet; returns results per line */
  evalSheet: (lines: string[]) => void
  /** The most recent evaluation results, one per input line */
  results: EngineLineResult[]
  /** Error from the last evaluation, if any */
  error: string | null
}

export function useEngine(): EngineState {
  const workerRef = useRef<Worker | null>(null)
  const requestIdRef = useRef(0)
  const latestIdRef = useRef(0)
  const [ready, setReady] = useState(false)
  const [results, setResults] = useState<EngineLineResult[]>([])
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const worker = new Worker(
      new URL('./worker.ts', import.meta.url),
      { type: 'module' },
    )
    workerRef.current = worker

    worker.onmessage = (event: MessageEvent<WorkerResponse>) => {
      const msg = event.data

      switch (msg.kind) {
        case 'ready':
          setReady(true)
          break

        case 'initError':
          setError(msg.error)
          break

        case 'evalResult':
          // Only apply if this is the most recent request
          if (msg.id === latestIdRef.current) {
            setResults(msg.results)
            setError(null)
          }
          break

        case 'evalError':
          if (msg.id === latestIdRef.current) {
            setError(msg.error)
          }
          break
      }
    }

    worker.onerror = (err) => {
      setError(`Worker error: ${err.message}`)
    }

    // Initialize the worker (trigger WASM loading)
    worker.postMessage({ kind: 'init' })

    return () => {
      worker.terminate()
      workerRef.current = null
    }
  }, [])

  const evalSheet = useCallback((lines: string[]) => {
    if (!workerRef.current) return

    const id = ++requestIdRef.current
    latestIdRef.current = id

    workerRef.current.postMessage({
      kind: 'evalSheet',
      id,
      lines,
    })
  }, [])

  return { ready, evalSheet, results, error }
}
