'use client'

import { useCallback, useEffect, useRef, useState } from 'react'
import { Pause, Play, RotateCcw, StepForward } from 'lucide-react'
import { PageMd } from '@/components/interactive-page/page-md'
import type { AnimBeat, SimI18n } from '@/lib/simulators'
import { cn } from '@/lib/utils'

const WPM = 220
const STEP_FLOOR_MS = 1500
const STEP_CEIL_MS = 6000
const SPEEDS = [0.5, 1, 2, 4]

function stepDurationMs(speak: string, speed: number): number {
  const words = speak.trim().split(/\s+/).filter(Boolean).length
  const raw = words * (60_000 / WPM)
  return Math.min(STEP_CEIL_MS, Math.max(STEP_FLOOR_MS, raw)) / speed
}

function usePrefersReducedMotion(): boolean {
  const [reduced, setReduced] = useState(false)
  useEffect(() => {
    const mq = window.matchMedia('(prefers-reduced-motion: reduce)')
    setReduced(mq.matches)
    const onChange = () => setReduced(mq.matches)
    mq.addEventListener('change', onChange)
    return () => mq.removeEventListener('change', onChange)
  }, [])
  return reduced
}

export type AnimPlayerShellProps = {
  beats: AnimBeat[]
  lang: string
  disclaimer?: SimI18n
  /** Scene renderer — receives the current beat index (0-based). */
  children: (stepIndex: number) => React.ReactNode
}

/**
 * Shared chrome for curated animation plugins: Play/Pause/Step/Reset/Speed
 * + narration panel, same pacing rules as InteractiveDemoPlayer.
 */
export function AnimPlayerShell({
  beats,
  lang,
  disclaimer,
  children,
}: AnimPlayerShellProps) {
  const fr = lang.startsWith('fr')
  const reducedMotion = usePrefersReducedMotion()
  const [stepIndex, setStepIndex] = useState(0)
  const [playing, setPlaying] = useState(false)
  const [speed, setSpeed] = useState(1)
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  /** Keyboard shortcuts only fire for the hovered/focused player. */
  const activeRef = useRef(false)

  const clearTimer = useCallback(() => {
    if (timerRef.current) {
      clearTimeout(timerRef.current)
      timerRef.current = null
    }
  }, [])

  const atLast = stepIndex >= beats.length - 1

  useEffect(() => {
    clearTimer()
    if (!playing) return
    const beat = beats[stepIndex]
    if (!beat) return
    const speak = fr ? beat.speak.fr : beat.speak.en
    timerRef.current = setTimeout(
      () => {
        if (stepIndex >= beats.length - 1) {
          setPlaying(false)
          return
        }
        setStepIndex((s) => s + 1)
      },
      reducedMotion ? 250 : stepDurationMs(speak, speed)
    )
    return clearTimer
  }, [playing, stepIndex, beats, speed, fr, reducedMotion, clearTimer])

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      const tag = (e.target as HTMLElement)?.tagName
      if (tag === 'INPUT' || tag === 'TEXTAREA') return
      // Multi-player pages: only the hovered/focused player answers the keyboard
      if (!activeRef.current) return
      if (e.code === 'Space') {
        e.preventDefault()
        setPlaying((p) => !p)
      } else if (e.code === 'ArrowRight') {
        e.preventDefault()
        setPlaying(false)
        setStepIndex((s) => Math.min(beats.length - 1, s + 1))
      } else if (e.code === 'ArrowLeft') {
        e.preventDefault()
        setPlaying(false)
        setStepIndex((s) => Math.max(0, s - 1))
      } else if (e.code === 'KeyR') {
        e.preventDefault()
        setPlaying(false)
        setStepIndex(0)
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [beats.length])

  const beat = beats[stepIndex]
  const speak = beat ? (fr ? beat.speak.fr : beat.speak.en) : ''

  return (
    <div
      onPointerEnter={() => {
        activeRef.current = true
      }}
      onPointerLeave={() => {
        activeRef.current = false
      }}
      onFocusCapture={() => {
        activeRef.current = true
      }}
      onBlurCapture={() => {
        activeRef.current = false
      }}
    >
      <div className="overflow-hidden rounded-xl border" style={{ borderColor: 'var(--pp-line)' }}>
        {children(stepIndex)}
      </div>

      <div
        className="mt-2 flex flex-wrap items-center gap-1 rounded-lg border px-2 py-1.5"
        style={{ borderColor: 'var(--pp-line)', background: 'var(--pp-card)' }}
      >
        <button
          type="button"
          onClick={() => setPlaying((p) => !p)}
          aria-label={playing ? 'Pause' : 'Play'}
          className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-black/5 dark:hover:bg-white/10"
          style={{ color: 'var(--pp-plum)' }}
        >
          {playing ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
        </button>
        <button
          type="button"
          onClick={() => {
            setPlaying(false)
            setStepIndex((s) => Math.min(beats.length - 1, s + 1))
          }}
          aria-label={fr ? 'Étape suivante' : 'Next step'}
          className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-black/5 dark:hover:bg-white/10"
          style={{ color: 'var(--pp-ink)' }}
        >
          <StepForward className="h-4 w-4" />
        </button>
        <button
          type="button"
          onClick={() => {
            setPlaying(false)
            setStepIndex(0)
          }}
          aria-label="Reset"
          title="R"
          className="inline-flex h-8 w-8 items-center justify-center rounded-md hover:bg-black/5 dark:hover:bg-white/10"
          style={{ color: 'var(--pp-ink)' }}
        >
          <RotateCcw className="h-4 w-4" />
        </button>

        <span
          className="ml-2 text-xs tabular-nums"
          style={{ color: 'var(--pp-muted)', fontFamily: 'var(--pp-mono)' }}
        >
          {fr ? 'étape' : 'step'} {stepIndex + 1} / {beats.length}
        </span>

        <div
          className="ml-auto flex items-center gap-0.5 rounded-md border p-0.5"
          style={{ borderColor: 'var(--pp-line)' }}
          role="group"
          aria-label={fr ? 'Vitesse' : 'Speed'}
        >
          {SPEEDS.map((s) => (
            <button
              key={s}
              type="button"
              onClick={() => setSpeed(s)}
              className={cn(
                'rounded px-1.5 py-0.5 text-[11px] tabular-nums transition-colors',
                speed === s ? 'font-semibold' : 'opacity-60 hover:opacity-100'
              )}
              style={
                speed === s
                  ? { background: 'var(--pp-ink)', color: 'var(--pp-paper)' }
                  : { color: 'var(--pp-muted)' }
              }
            >
              {s}×
            </button>
          ))}
        </div>
      </div>

      <div
        className="mt-2 rounded-lg border px-4 py-3"
        style={{ borderColor: 'var(--pp-line)', background: 'var(--pp-card)' }}
      >
        <PageMd md={speak} className="text-[15px] leading-relaxed [&_p]:my-0" />
      </div>

      {disclaimer ? (
        <p className="mt-2 text-xs italic" style={{ color: 'var(--pp-muted)' }}>
          {fr ? disclaimer.fr : disclaimer.en}
        </p>
      ) : null}

      <noscript>
        <ol className="mt-3 list-inside list-decimal space-y-1 text-sm">
          {beats.map((b) => (
            <li key={b.id}>{fr ? b.speak.fr : b.speak.en}</li>
          ))}
        </ol>
      </noscript>
    </div>
  )
}
