// Det. Hale — your partner on the wire. Contextual, spoiler-safe hints from the server,
// plus one-time local nudges that introduce each screen to a new player.
import { useEffect, useState } from 'preact/hooks'

import { getHint } from '../api'
import { useTypewriter } from '../engine/pixel'
import { type Screen, useGame } from '../store'
import { hasSeen, markSeen } from '../tips'
import { Portrait } from './components'

const HIDDEN = new Set(['title', 'verdict', 'share', 'boot'])
const FALLBACK = 'Work the evidence, detective. Find where a statement and a fact disagree, and press there.'

// First-visit nudges (client-local, no server call). Shown once per browser.
const TIPS: Partial<Record<Screen, string>> = {
  board: 'Pick a suspect and lean on them. Work the checklist on the rail — question everyone, show them the exhibits.',
  interro: 'Ask your questions, then hit them with evidence from the tray. Watch that bar climb.',
  accuse: 'Name them, give me the why, and attach what made them crack.',
}

export function Assistant() {
  const g = useGame()
  const [open, setOpen] = useState(false)
  const [hint, setHint] = useState('')
  const [localTip, setLocalTip] = useState<string | null>(null)
  const screen = g.state.screen

  useEffect(() => {
    const t = () => {
      setLocalTip(null) // HINT button always fetches the live server hint
      setOpen((o) => !o)
    }
    const c = () => setOpen(false)
    window.addEventListener('toggle-hint', t)
    window.addEventListener('close-hint', c)
    return () => {
      window.removeEventListener('toggle-hint', t)
      window.removeEventListener('close-hint', c)
    }
  }, [])

  // Screen change: close whatever was open, then fire the one-time nudge for this
  // screen kind. On the board it waits for the case-brief overlay to be dismissed
  // so the two never stack.
  useEffect(() => {
    setOpen(false)
    setLocalTip(null)
    const tip = TIPS[screen]
    if (!tip || hasSeen(`tip:${screen}`)) return
    let timer: ReturnType<typeof setTimeout> | null = null
    const show = () => {
      markSeen(`tip:${screen}`)
      setLocalTip(tip)
      setOpen(true)
    }
    const briefPending = screen === 'board' && !hasSeen(`brief:${g.case.id}`)
    const onBrief = () => {
      timer = setTimeout(show, 400)
    }
    if (briefPending) window.addEventListener('cz-brief-done', onBrief, { once: true })
    else timer = setTimeout(show, 700)
    return () => {
      if (timer) clearTimeout(timer)
      window.removeEventListener('cz-brief-done', onBrief)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [screen])

  useEffect(() => {
    if (!open || localTip) return
    let alive = true
    setHint('')
    getHint(g.runId, screen)
      .then((r) => {
        if (alive) setHint(r.hint || FALLBACK)
      })
      .catch(() => {
        if (alive) setHint(FALLBACK)
      })
    return () => {
      alive = false
    }
  }, [open, localTip, screen, g.runId])

  const [typed, done] = useTypewriter(open ? localTip ?? hint : '', g.state.tweaks.typeSpeed || 18, open)

  if (HIDDEN.has(screen) || !open) return null
  return (
    <div class="assistant">
      <div class="assistant__panel">
        <div class="between" style={{ marginBottom: 8 }}>
          <div class="row" style={{ gap: 8, alignItems: 'center' }}>
            <div style={{ background: 'var(--ink-1)', boxShadow: 'inset 0 0 0 2px var(--ink-0)', padding: 2 }}>
              <Portrait id="detective" px={3} />
            </div>
            <div class="col" style={{ gap: 1 }}>
              <span class="t-display amber" style={{ fontSize: 9 }}>DET. HALE</span>
              <span class="t-label" style={{ fontSize: 7 }}>YOUR PARTNER · ON THE WIRE</span>
            </div>
          </div>
          <button class="assistant__x" onClick={() => setOpen(false)}>✕</button>
        </div>
        <p class="t-body" style={{ fontSize: 14, lineHeight: 1.5, color: 'var(--bone-2)' }}>
          “{typed}
          {!done && <span class="cursor" />}”
        </p>
      </div>
    </div>
  )
}
