'use client'

import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import {
  Pause,
  Play,
  RotateCcw,
  SkipBack,
  SkipForward,
  StepBack,
  StepForward,
} from 'lucide-react'
import { DemoSceneView } from '@/components/interactive-demo/demo-scene-view'
import { DemoSpeak } from '@/components/interactive-demo/demo-speak'
import {
  resolveInteractiveDemo,
  type InteractiveDemoV1,
} from '@/lib/interactive-demo'
import { cn } from '@/lib/utils'
import { useLanguage } from '@/lib/i18n'

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

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
}

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

export type InteractiveDemoPlayerProps = {
  demo: InteractiveDemoV1
  mode?: 'interactive' | 'static'
  className?: string
}

export function InteractiveDemoPlayer({
  demo,
  mode = 'interactive',
  className,
}: InteractiveDemoPlayerProps) {
  const { t } = useLanguage()
  const reducedMotion = usePrefersReducedMotion()
  const resolved = useMemo(() => resolveInteractiveDemo(demo), [demo])

  const [actIndex, setActIndex] = useState(0)
  const [stepIndex, setStepIndex] = useState(0)
  const [playing, setPlaying] = useState(false)
  const [speedIdx, setSpeedIdx] = useState(1)
  const speed = SPEEDS[speedIdx] ?? 1
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const actPauseRef = useRef(false)
  /** Keyboard shortcuts only fire for the hovered/focused player. */
  const activeRef = useRef(false)

  const act = resolved.acts[actIndex] ?? resolved.acts[0]
  const scenes = useMemo(() => {
    let scene = demo.scene
    const map: (typeof demo.scene)[] = []
    for (const a of demo.acts) {
      if (a.scene) scene = a.scene
      map.push(scene)
    }
    return map
  }, [demo])

  const scene = scenes[actIndex] ?? demo.scene

  const state =
    mode === 'static'
      ? act?.final
      : act?.steps[stepIndex] ?? act?.final

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

  const goStep = useCallback(
    (next: number) => {
      if (!act) return
      if (next < 0) {
        setStepIndex(0)
        return
      }
      if (next >= act.steps.length) {
        setPlaying(false)
        setStepIndex(act.steps.length - 1)
        return
      }
      setStepIndex(next)
    },
    [act]
  )

  const resetAct = useCallback(() => {
    clearTimer()
    actPauseRef.current = false
    setPlaying(false)
    setStepIndex(0)
  }, [clearTimer])

  const resetDemo = useCallback(() => {
    clearTimer()
    actPauseRef.current = false
    setPlaying(false)
    setActIndex(0)
    setStepIndex(0)
  }, [clearTimer])

  const skipAct = useCallback(() => {
    clearTimer()
    actPauseRef.current = false
    setPlaying(false)
    if (actIndex >= resolved.acts.length - 1) {
      setStepIndex((act?.steps.length ?? 1) - 1)
      return
    }
    setActIndex((i) => i + 1)
    setStepIndex(0)
  }, [actIndex, act, resolved.acts.length, clearTimer])

  const prevAct = useCallback(() => {
    clearTimer()
    actPauseRef.current = false
    setPlaying(false)
    if (actIndex <= 0) {
      setStepIndex(0)
      return
    }
    setActIndex((i) => i - 1)
    setStepIndex(0)
  }, [actIndex, clearTimer])

  // Auto-play: duration recalculates immediately when speed/step changes
  useEffect(() => {
    clearTimer()
    if (!playing || mode !== 'interactive' || !act || !state) return

    const atLastStep = stepIndex >= act.steps.length - 1
    const ms = stepDurationMs(state.speak, speed)

    timerRef.current = setTimeout(() => {
      if (atLastStep) {
        // End of act while playing
        if (actIndex < resolved.acts.length - 1) {
          actPauseRef.current = true
          timerRef.current = setTimeout(() => {
            actPauseRef.current = false
            setActIndex((i) => i + 1)
            setStepIndex(0)
          }, ACT_CHANGE_PAUSE_MS)
        } else {
          // End of demo — pause on final state
          setPlaying(false)
        }
        return
      }
      setStepIndex((s) => s + 1)
    }, ms)

    return clearTimer
  }, [
    playing,
    stepIndex,
    speed,
    act,
    state,
    mode,
    actIndex,
    resolved.acts.length,
    clearTimer,
  ])

  useEffect(() => {
    if (mode !== 'interactive') return
    const onKey = (e: KeyboardEvent) => {
      const tag = (e.target as HTMLElement)?.tagName
      if (
        tag === 'INPUT' ||
        tag === 'TEXTAREA' ||
        (e.target as HTMLElement)?.isContentEditable
      ) {
        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.shiftKey) {
        e.preventDefault()
        skipAct()
      } else if (e.code === 'ArrowLeft' && e.shiftKey) {
        e.preventDefault()
        prevAct()
      } else if (e.code === 'ArrowRight') {
        e.preventDefault()
        setPlaying(false)
        goStep(stepIndex + 1)
      } else if (e.code === 'ArrowLeft') {
        e.preventDefault()
        setPlaying(false)
        goStep(stepIndex - 1)
      } else if (e.code === 'KeyR' && e.shiftKey) {
        e.preventDefault()
        resetDemo()
      } else if (e.code === 'KeyR') {
        e.preventDefault()
        resetAct()
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [mode, stepIndex, goStep, resetAct, resetDemo, skipAct, prevAct])

  if (!act || !state || !scene) {
    return (
      <div className="rounded-lg border border-dashed border-border p-4 text-sm text-muted-foreground">
        {t('interactiveDemo.empty') || 'Interactive demo unavailable'}
      </div>
    )
  }

  const progressLabel = `${act.title} · ${t('interactiveDemo.step') || 'étape'} ${stepIndex + 1} / ${act.steps.length}`

  return (
    <div
      className={cn(
        'interactive-demo-player my-4 overflow-hidden rounded-2xl border border-border/80 bg-card text-card-foreground shadow-sm',
        className
      )}
      data-demo-id={demo.id}
      data-mode={mode}
      onPointerEnter={() => {
        activeRef.current = true
      }}
      onPointerLeave={() => {
        activeRef.current = false
      }}
      onFocusCapture={() => {
        activeRef.current = true
      }}
      onBlurCapture={() => {
        activeRef.current = false
      }}
    >
      {demo.disclaimer && (
        <p className="border-b border-border/40 bg-muted/30 px-4 py-2.5 text-[11px] leading-relaxed text-muted-foreground italic">
          {demo.disclaimer}
        </p>
      )}

      <div className="p-3 sm:p-4">
        <DemoSceneView
          scene={scene}
          state={state}
          reducedMotion={reducedMotion || mode === 'static'}
        />
      </div>

      <div className="border-t border-border/50 bg-gradient-to-b from-muted/40 to-muted/10 px-4 pb-3 pt-1">
        <DemoSpeak
          speak={state.speak}
          className="py-3 text-[15px] leading-relaxed text-foreground/90 prose prose-sm dark:prose-invert max-w-none [&>p]:my-0 [&>p]:font-medium"
        />
        <div className="flex items-center justify-between gap-2 pb-2.5 text-[11px] uppercase tracking-wide text-muted-foreground">
          <span className="truncate font-semibold normal-case tracking-normal text-foreground/70">
            {progressLabel}
          </span>
        </div>

        {mode === 'interactive' && (
          <div className="flex flex-wrap items-center gap-2 pb-2">
            <div className="flex items-center gap-1 rounded-lg border border-border/70 bg-background/80 p-0.5 shadow-sm">
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md bg-primary text-primary-foreground hover:opacity-90"
                onClick={() => setPlaying((p) => !p)}
                aria-label={playing ? 'Pause' : 'Play'}
              >
                {playing ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
              </button>
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground/80 hover:bg-muted"
                onClick={() => {
                  setPlaying(false)
                  goStep(stepIndex - 1)
                }}
                aria-label="Previous step"
              >
                <StepBack className="h-4 w-4" />
              </button>
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground/80 hover:bg-muted"
                onClick={() => {
                  setPlaying(false)
                  goStep(stepIndex + 1)
                }}
                aria-label="Next step"
              >
                <StepForward className="h-4 w-4" />
              </button>
              <div className="mx-0.5 h-5 w-px bg-border" />
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground/80 hover:bg-muted"
                onClick={prevAct}
                aria-label="Previous act"
              >
                <SkipBack className="h-4 w-4" />
              </button>
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground/80 hover:bg-muted"
                onClick={skipAct}
                aria-label="Next act"
              >
                <SkipForward className="h-4 w-4" />
              </button>
              <button
                type="button"
                className="inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground/80 hover:bg-muted"
                onClick={resetAct}
                aria-label="Reset act"
                title="R"
              >
                <RotateCcw className="h-4 w-4" />
              </button>
            </div>

            <div
              className="ml-auto flex items-center gap-0.5 rounded-lg border border-border/70 bg-background/80 p-0.5 shadow-sm"
              role="group"
              aria-label={t('interactiveDemo.speed') || 'Vitesse'}
            >
              {SPEEDS.map((s, i) => (
                <button
                  key={s}
                  type="button"
                  onClick={() => setSpeedIdx(i)}
                  aria-pressed={speedIdx === i}
                  className={cn(
                    'h-7 min-w-[2.35rem] rounded-md px-1.5 text-xs font-semibold tabular-nums transition-colors',
                    speedIdx === i
                      ? 'bg-primary text-primary-foreground'
                      : 'text-muted-foreground hover:bg-muted hover:text-foreground'
                  )}
                >
                  {s}×
                </button>
              ))}
            </div>
          </div>
        )}
      </div>

      <noscript>
        <ol className="space-y-1 list-inside list-decimal px-4 pb-4 text-sm">
          {act.steps.map((s) => (
            <li key={s.stepId}>{s.speak}</li>
          ))}
        </ol>
      </noscript>
    </div>
  )
}
