// Root shell: loads the case from the server (or ?case=ID), then mounts the game.
import { useEffect, useState } from 'preact/hooks'

import { type CaseResponse, getCase, newCase } from './api'
import { RainFX, prefersReducedMotion } from './engine/pixel'
import { getCaseTheme, setCaseTheme, themeFromCase } from './engine/theme'
import { getPlayed, markPlayed } from './played'
import { GameProvider, type Screen, useGame, useMode, useTweaks } from './store'
import type { PublicCase } from './types'
import { SCREENS } from './screens'
import { TitleScreen } from './screens/cold'
import { Assistant } from './ui/assistant'
import { unlockAudioOnce } from './ui/audio'
import { Btn } from './ui/components'

const RAIN_SCREENS = new Set(['title', 'interro', 'briefing', 'verdict', 'flashback', 'story'])

function ScreenHost() {
  const g = useGame()
  const Screen = SCREENS[g.state.screen] || TitleScreen
  const t = g.state.tweaks
  const wet = ['rain', 'sleet'].includes(getCaseTheme().weather)
  const showRain = wet && t.rain && t.fx !== 'low' && !prefersReducedMotion() && RAIN_SCREENS.has(g.state.screen)
  return (
    <div class="app__stage">
      <div class="app__frame">
        <Screen key={g.state.screen} />
        <div class="fx-layer fx-scanlines" />
        <div class="fx-layer fx-vignette" />
        <div class="fx-layer fx-flicker" />
        {showRain && (
          <div class="fx-layer">
            <RainFX density={t.fx === 'high' ? 130 : 80} />
          </div>
        )}
      </div>
      <Assistant />
    </div>
  )
}

function Loading() {
  const showRain = !prefersReducedMotion()
  return (
    <div class="app__stage">
      <div class="app__frame" style={{ position: 'relative', background: 'var(--ink-0)' }}>
        {showRain && (
          <div class="fx-layer">
            <RainFX density={80} />
          </div>
        )}
        <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(80% 70% at 50% 45%, transparent 35%, rgba(8,11,16,.85) 100%)' }} />
        <div class="screen-center" style={{ position: 'relative', zIndex: 2 }}>
          <div class="col center" style={{ gap: 14, textAlign: 'center' }}>
            <div class="t-label" style={{ letterSpacing: '.34em', color: 'var(--amber-2)' }}>CASE ZERO</div>
            <div class="t-display" style={{ fontSize: 'clamp(18px,4vw,28px)', color: 'var(--bone-3)' }}>FORMING A CASE<span class="cursor" /></div>
            <div class="t-mono dim" style={{ fontSize: 'calc(15px*var(--mono-scale))', maxWidth: 320 }}>The city, the body, the lies — coming together from the night wire.</div>
          </div>
        </div>
        <div class="fx-layer fx-scanlines" />
        <div class="fx-layer fx-vignette" />
      </div>
    </div>
  )
}

function ErrorView({ msg, retry }: { msg: string; retry: () => void }) {
  return (
    <div class="app__stage">
      <div class="app__frame">
        <div class="screen-center">
          <div class="panel panel--ox col center" style={{ gap: 14, maxWidth: 420, textAlign: 'center', padding: 24 }}>
            <div class="t-display ox" style={{ fontSize: 14 }}>THE WIRE WENT DEAD</div>
            <div class="t-body" style={{ color: 'var(--bone-2)' }}>{msg}</div>
            <Btn variant="amber" onClick={retry}>Try again</Btn>
          </div>
        </div>
      </div>
    </div>
  )
}

export function Root() {
  const [data, setData] = useState<{ case: PublicCase; runId: string } | null>(null)
  const [error, setError] = useState<string | null>(null)
  const [startScreen, setStartScreen] = useState<Screen>('title')
  const mode = useMode('auto')  // always responsive to the real viewport
  const [tweaks, setTweak] = useTweaks()

  useEffect(() => {
    const r = document.documentElement
    r.setAttribute('data-palette', tweaks.palette)
    r.setAttribute('data-fonts', tweaks.fonts)
    r.setAttribute('data-fx', tweaks.fx)
    r.setAttribute('data-mood', tweaks.mood)
    window.__pxScale = tweaks.pixelScale
  }, [tweaks])

  useEffect(unlockAudioOnce, []) // grant audio playback on first tap (mobile autoplay policy)

  // Every path a case arrives through: set its visual theme and remember it as
  // played (so New Case never deals this browser the same mystery again).
  const apply = (r: CaseResponse) => {
    setCaseTheme(themeFromCase(r.case))
    markPlayed(r.case.id)
    setData({ case: r.case, runId: r.runId })
  }

  const load = () => {
    setError(null)
    setData(null)
    setStartScreen('title')
    const params = new URLSearchParams(window.location.search)
    const cid = params.get('case')
    const req = cid ? getCase(cid) : newCase({ excludeCaseIds: getPlayed() })
    req.then(apply).catch((e) => setError(e instanceof Error ? e.message : String(e)))
  }
  useEffect(load, [])

  // "Begin New Case" - always fetch a FRESH case from the server (never replay the loaded one)
  // and start playing it. A shared ?case= is cleared so a refresh won't snap back to it.
  const beginNewCase = () => {
    setError(null)
    setData(null)
    setStartScreen('story')
    const u = new URL(window.location.href)
    if (u.searchParams.has('case')) {
      u.searchParams.delete('case')
      window.history.replaceState({}, '', u.pathname + u.search)
    }
    newCase({ excludeCaseIds: getPlayed() })
      .then(apply)
      .catch((e) => setError(e instanceof Error ? e.message : String(e)))
  }

  // "Enter Case ID" - load that exact case (fresh run) and jump straight into playing it.
  const loadCaseById = (id: string) => {
    const cid = id.trim()
    if (!cid) return
    setError(null)
    setData(null)
    setStartScreen('story')
    const u = new URL(window.location.href)
    u.searchParams.set('case', cid)
    window.history.replaceState({}, '', u.pathname + u.search)
    getCase(cid)
      .then(apply)
      .catch((e) => setError(e instanceof Error ? e.message : String(e)))
  }

  if (error) {
    return (
      <div class="app" data-mode={mode}>
        <ErrorView msg={error} retry={load} />
      </div>
    )
  }
  if (!data) {
    return (
      <div class="app" data-mode={mode}>
        <Loading />
      </div>
    )
  }
  return (
    <div class="app" data-mode={mode}>
      <GameProvider key={data.runId} case={data.case} runId={data.runId} mode={mode} tweaks={tweaks} setTweak={setTweak} initialScreen={startScreen} newCase={beginNewCase} loadCase={loadCaseById}>
        <ScreenHost />
      </GameProvider>
    </div>
  )
}
