import { useCallback, useEffect, useRef, useState } from 'react'
import { Settings } from './Settings'
import type { PoseSettings } from './types'
import { loadSettings, saveSettings } from './types'
import { usePoseLoop } from './pose/usePoseLoop'
import { ENTER_THRESHOLD, EXIT_THRESHOLD } from './gesture/detectors/crossedArmsDetector'
import { GestureOverlay } from './components/GestureOverlay'
import { ArrowGame } from './game/ArrowGame'
import type { ArrowGameHandle } from './game/ArrowGame'
import type { AudioPlayer } from './game/audioPlayer'
import { createLocalAudioPlayer } from './game/audioPlayer'
import { loadSSC } from './game/sscParser'
import type { ChartNote, ParsedChart } from './game/sscParser'
import { SONGS } from './game/songIndex'
import { StepGraphs } from './StepGraphs'
import { Pose3DView } from './components/Pose3DView'
import { getLog } from './debugLog'
import { playSound, SFX_BUTTON_DEFAULT } from './lib/sounds'
import './App.css'

const DEFAULT_SONG = 'get-lucky'

export function DebugApp() {
  const videoRef = useRef<HTMLVideoElement>(null)
  const canvasRef = useRef<HTMLCanvasElement>(null)
  const arCanvasRef = useRef<HTMLCanvasElement>(null)
  const arrowGameRef = useRef<ArrowGameHandle>(null)

  const [settings, setSettings] = useState<PoseSettings>(loadSettings)
  const [settingsOpen, setSettingsOpen] = useState(false)
  const [showFullscreenPrompt, setShowFullscreenPrompt] = useState(true)

  const [selectedSongId, setSelectedSongId] = useState(DEFAULT_SONG)
  const [chart, setChart] = useState<ParsedChart | null>(null)
  const [selectedDifficulty, setSelectedDifficulty] = useState('Beginner')
  const [chartNotes, setChartNotes] = useState<ChartNote[] | undefined>(undefined)
  const [audioPlayer, setAudioPlayer] = useState<AudioPlayer | null>(null)

  // Load chart when song changes
  useEffect(() => {
    const song = SONGS.find(s => s.id === selectedSongId)
    if (!song) return

    setChart(null)
    setChartNotes(undefined)
    audioPlayer?.destroy()
    setAudioPlayer(createLocalAudioPlayer(song.audioUrl))

    loadSSC(song.chartUrl).then(parsed => {
      setChart(parsed)
      // Default to Beginner, fall back to easiest available
      const diff = parsed.difficulties.find(d => d.difficulty === 'Beginner')
        || parsed.difficulties.reduce((a, b) => a.meter < b.meter ? a : b)
      if (diff) {
        setSelectedDifficulty(diff.difficulty)
        setChartNotes(diff.notes)
      }
    }).catch(() => {})
  }, [selectedSongId])

  // Update notes when difficulty changes
  useEffect(() => {
    if (!chart) return
    const diff = chart.difficulties.find(d => d.difficulty === selectedDifficulty)
    if (diff) setChartNotes(diff.notes)
  }, [chart, selectedDifficulty])

  const [crossedArms, setCrossedArms] = useState(false)

  const {
    loading, error, fps, gesture, calibrationStatus, framingHint,
    stepGraphSamples, landmarks2D, worldLandmarks, telemetry, engine,
  } = usePoseLoop(videoRef, canvasRef, arCanvasRef, settings, null, {
    onStep: (direction) => arrowGameRef.current?.handleStep(direction),
    onCrossedArmsStart: () => setCrossedArms(true),
    onCrossedArmsEnd: () => setCrossedArms(false),
  })

  const gameReady = calibrationStatus === 'ready'
  const [glow, setGlow] = useState<{ color: string; key: number } | null>(null)

  const handleJudgment = useCallback((j: 'perfect' | 'good' | 'miss') => {
    const colors = { perfect: '#00ff6a', good: '#ffe600', miss: '#ff2222' }
    setGlow({ color: colors[j], key: Date.now() })
  }, [])

  return (
    <div className="webcam-container">
      {showFullscreenPrompt && (
        <div className="fullscreen-prompt">
          <button
            type="button"
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              document.documentElement.requestFullscreen().catch(() => {})
              setShowFullscreenPrompt(false)
            }}
          >
            Go Fullscreen
          </button>
          <button
            type="button"
            className="skip"
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              setShowFullscreenPrompt(false)
            }}
          >
            Skip
          </button>
        </div>
      )}
      {loading && <div className="status">Loading pose detection...</div>}
      {error && <div className="status error">{error}</div>}
      <video ref={videoRef} className="webcam-video" playsInline muted />
      <canvas ref={canvasRef} className="pose-overlay" />
      <canvas ref={arCanvasRef} className="ar-overlay" />
      {(calibrationStatus === 'framing' || calibrationStatus === 'paused') && (
        <div className="framing-line" />
      )}
      <GestureOverlay
        gesture={gesture}
        calibrationStatus={calibrationStatus}
        framingHint={framingHint}
      />
      {glow && (
        <div
          key={glow.key}
          className="judgment-glow"
          style={{ '--glow-color': glow.color } as React.CSSProperties}
          onAnimationEnd={() => setGlow(null)}
        />
      )}
      <ArrowGame
        ref={arrowGameRef}
        active={gameReady}
        chartNotes={chartNotes}
        audioPlayer={audioPlayer}
        onJudgment={handleJudgment}
      />
      {gameReady && gesture && (
        <div className="detected-step">{gesture.replace('step-', '').toUpperCase()}</div>
      )}
      {(() => {
        const dist = engine?.crossedArmsDistances
        const holding = engine?.crossedArmsHolding ?? false
        const thr = crossedArms ? EXIT_THRESHOLD : ENTER_THRESHOLD
        return (
          <div style={{
            position: 'fixed', top: 20, left: '50%', transform: 'translateX(-50%)',
            background: crossedArms ? 'rgba(255, 100, 0, 0.85)' : holding ? 'rgba(255, 200, 0, 0.8)' : 'rgba(0, 0, 0, 0.7)',
            color: '#fff', padding: '8px 16px', borderRadius: 8,
            fontFamily: 'monospace', zIndex: 200, textAlign: 'center', fontSize: 13,
          }}>
            {crossedArms && <div style={{ fontSize: 20, fontWeight: 'bold' }}>CROSSED ARMS</div>}
            {holding && !crossedArms && <div style={{ fontSize: 16, fontWeight: 'bold' }}>HOLDING...</div>}
            <div>
              L→R {dist?.left.toFixed(2) ?? '—'}
              {' | '}
              R→L {dist?.right.toFixed(2) ?? '—'}
              {' | '}
              thr {thr.toFixed(2)}
            </div>
          </div>
        )
      })()}
      {settings.showDebug && (
        <>
          <StepGraphs
            samples={stepGraphSamples}
            thresholdX={settings.stepThresholdX}
            thresholdZ={settings.stepThresholdZ}
            reset={settings.stepReset}
          />
          <Pose3DView landmarks={worldLandmarks} landmarks2D={landmarks2D} />
          <button
            type="button"
            className="copy-log-btn"
            onClick={() => {
              playSound(SFX_BUTTON_DEFAULT)
              const stepData = JSON.stringify(telemetry?.stepLog ?? [])
              const full = getLog() + '\n\n=== STEP LOG (full) ===\n' + stepData
              navigator.clipboard.writeText(full)
                .then(() => alert('Log + step data copied!'))
            }}
          >
            Copy Log
          </button>
        </>
      )}
      <Settings
        settings={settings}
        onChange={(s) => { saveSettings(s); setSettings(s) }}
        open={settingsOpen}
        onToggle={() => setSettingsOpen(!settingsOpen)}
        fps={fps}
        songs={SONGS.map(s => ({ id: s.id, title: s.title }))}
        selectedSong={selectedSongId}
        onSongChange={setSelectedSongId}
        difficulties={chart?.difficulties.map(d => ({ label: d.difficulty, meter: d.meter }))}
        selectedDifficulty={selectedDifficulty}
        onDifficultyChange={setSelectedDifficulty}
      />
    </div>
  )
}
