import { useCallback, useEffect, useState } from 'react'
import { CutsceneHost, DialoguePlayer, SplashScreen, type PlaythroughState } from './narrative'

// The game's front door and campaign runtime. Shows the splash when there's no
// active playthrough; otherwise walks the story graph — cutscene and dialogue
// nodes render here, and when the graph reaches a LEVEL node it hands off to the
// board route (/level/<clone id>), which App renders.
export function Play() {
  const [state, setState] = useState<PlaythroughState | null>(null)
  const [splash, setSplash] = useState(false)
  const [busy, setBusy] = useState(false)
  const [status, setStatus] = useState('')

  const apply = useCallback((next: PlaythroughState | null) => {
    if (!next) { setSplash(true); return }
    if (next.node?.kind === 'level' && next.node.levelSlug) { window.location.assign(`/level/${encodeURIComponent(next.node.levelSlug)}`); return }
    if (!next.node) { setState(null); setSplash(true); setStatus('CASE CLOSED — begin another'); return }
    setState(next); setSplash(false)
  }, [])

  const ensurePlaythroughId = async (): Promise<string | null> => {
    const cur = await fetch('/api/playthroughs/current')
    if (cur.ok && cur.status !== 204) return (await cur.json())?.playthrough?.id ?? null
    const made = await fetch('/api/playthroughs', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ mystery: 'glass-harbor' }) })
    return made.ok ? (await made.json())?.playthrough?.id ?? null : null
  }

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      // /node/:id — dev teleport to a specific story node (level nodes -> the board).
      const nodeMatch = window.location.pathname.match(/^\/node\/(.+)$/)
      if (nodeMatch) {
        const id = await ensurePlaythroughId()
        if (cancelled || !id) { if (!cancelled) setStatus('NO PLAYTHROUGH'); return }
        const res = await fetch(`/api/playthroughs/${id}/goto`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ nodeId: decodeURIComponent(nodeMatch[1]) }) })
        if (!cancelled) res.ok ? apply(await res.json()) : setStatus('NODE NOT FOUND')
        return
      }
      const res = await fetch('/api/playthroughs/current')
      if (cancelled) return
      if (res.status === 204) { setSplash(true); setStatus('AWAITING PRINCIPAL INVESTIGATOR'); return }
      res.ok ? apply(await res.json()) : setSplash(true)
    })()
    return () => { cancelled = true }
  }, [apply])

  const newGame = async () => {
    setBusy(true)
    try {
      const res = await fetch('/api/playthroughs', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ mystery: 'glass-harbor' }) })
      if (res.ok) apply(await res.json())
      else setStatus('NO MYSTERY AVAILABLE')
    } finally { setBusy(false) }
  }

  const advance = async (terminalKey?: string) => {
    if (!state) return
    const res = await fetch(`/api/playthroughs/${state.playthrough.id}/advance`, {
      method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ terminalKey }),
    })
    if (res.ok) apply(await res.json())
  }

  if (splash) return <SplashScreen hasResume={false} busy={busy} status={status} onNewGame={newGame} onResume={() => {}} />

  const node = state?.node
  if (!node) return <div className="boot"><div className="seal">GU</div><p>GLITCH UNIVERSITY NETWORK TERMINAL</p><small>{status || 'OPENING CASE FILE…'}</small></div>
  if (node.kind === 'cutscene') return <CutsceneHost componentKey={node.componentKey} label={node.label} onComplete={() => { void advance() }} />
  if (node.kind === 'dialogue' && node.utterances) return <DialoguePlayer node={{ utterances: node.utterances, rootId: node.rootId ?? null }} onExit={terminalKey => { void advance(terminalKey) }} />
  return <div className="boot"><div className="seal">GU</div><small>{node.label}</small></div>
}
