'use client'

import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { motion, AnimatePresence } from 'motion/react'
import {
  GraduationCap,
  Layers,
  ArrowLeft,
  ChevronLeft,
  ChevronRight,
  Calendar,
  BarChart3,
  Loader2,
  BookOpen,
  Check,
  ChevronDown,
  Trash2,
  Pencil,
  X,
  BookMarked,
  Clock,
  Timer,
  Flame,
  TrendingUp,
} from 'lucide-react'
import { useSearchParams } from 'next/navigation'
import { useLanguage } from '@/lib/i18n'
import { cn } from '@/lib/utils'
import { NoteChart } from '@/components/note-chart'
import { RevisionHeatmap } from './revision-heatmap'
import { RetentionCurve } from './retention-curve'
import { toast } from 'sonner'

interface DeckSummary {
  id: string
  name: string
  notebookId: string | null
  notebookName: string | null
  totalCards: number
  dueCount: number
  masteredCount: number
  lastReviewedAt: string | null
  nextReviewAt: string | null
}

interface FlashcardItem {
  id: string
  front: string
  back: string
  type: string
  due: boolean
  mastered: boolean
}

interface StatsResponse {
  heatmap: { date: string; count: number }[]
  retentionRate: number
  retentionByWeek: { week: string; rate: number; total: number }[]
  difficultCards: { id: string; front: string; easinessFactor: number; deckId: string; deckName: string }[]
  totalReviews: number
  streak: number
  totalCards: number
  masteredCount: number
}

type PageTab = 'decks' | 'progress'
type SessionGrade = 1 | 2 | 3 | 4
type ReviewMode = 'due' | 'all'

function shuffleCards<T>(items: T[]): T[] {
  const arr = [...items]
  for (let i = arr.length - 1; i > 0; i -= 1) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[arr[i], arr[j]] = [arr[j], arr[i]]
  }
  return arr
}

function buildSessionQueue(cards: FlashcardItem[], dueOnly: boolean): FlashcardItem[] {
  const toReview = dueOnly ? cards.filter((c) => c.due) : cards
  return shuffleCards(toReview)
}

function formatDuration(seconds: number): string {
  const m = Math.floor(seconds / 60)
  const s = seconds % 60
  if (m === 0) return `${s}s`
  return `${m}m ${s}s`
}

const GRADE_OPTIONS: {
  grade: SessionGrade
  idle: string
  selected: string
  ring: string
}[] = [
  {
    grade: 1,
    idle: 'bg-red-500/10 text-red-600 border-red-500/20 hover:bg-red-500/15',
    selected: 'bg-red-500 text-white border-red-500 shadow-lg shadow-red-500/25',
    ring: 'ring-red-400/50',
  },
  {
    grade: 2,
    idle: 'bg-amber-500/10 text-amber-700 border-amber-500/20 hover:bg-amber-500/15',
    selected: 'bg-amber-500 text-white border-amber-500 shadow-lg shadow-amber-500/25',
    ring: 'ring-amber-400/50',
  },
  {
    grade: 3,
    idle: 'bg-emerald-500/10 text-emerald-700 border-emerald-500/20 hover:bg-emerald-500/15',
    selected: 'bg-emerald-500 text-white border-emerald-500 shadow-lg shadow-emerald-500/25',
    ring: 'ring-emerald-400/50',
  },
  {
    grade: 4,
    idle: 'bg-brand-accent/10 text-brand-accent border-brand-accent/30 hover:bg-brand-accent/15',
    selected: 'bg-brand-accent text-white border-brand-accent shadow-lg shadow-brand-accent/25',
    ring: 'ring-brand-accent/50',
  },
]

const TYPE_LABEL: Record<string, string> = {
  qa: 'Q&A',
  cloze: 'Cloze',
  concept: 'Concept',
}

/** Inline card editor inside the expanded deck list */
function CardEditRow({
  card,
  onSaved,
  onDeleted,
}: {
  card: FlashcardItem
  onSaved: (id: string, front: string, back: string) => void
  onDeleted: (id: string) => void
}) {
  const { t } = useLanguage()
  const [editing, setEditing] = useState(false)
  const [front, setFront] = useState(card.front)
  const [back, setBack] = useState(card.back)
  const [saving, setSaving] = useState(false)
  const [deleting, setDeleting] = useState(false)
  const [confirmDelete, setConfirmDelete] = useState(false)

  const handleSave = async () => {
    setSaving(true)
    try {
      const res = await fetch(`/api/flashcards/${card.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ front: front.trim(), back: back.trim() }),
      })
      if (!res.ok) throw new Error()
      onSaved(card.id, front.trim(), back.trim())
      setEditing(false)
      toast.success(t('flashcards.cardSaved'))
    } catch {
      toast.error(t('flashcards.deleteFailed'))
    } finally {
      setSaving(false)
    }
  }

  const handleDelete = async () => {
    setDeleting(true)
    try {
      const res = await fetch(`/api/flashcards/${card.id}`, { method: 'DELETE' })
      if (!res.ok) throw new Error()
      onDeleted(card.id)
      toast.success(t('flashcards.cardDeleted'))
    } catch {
      toast.error(t('flashcards.deleteFailed'))
    } finally {
      setDeleting(false)
      setConfirmDelete(false)
    }
  }

  if (editing) {
    return (
      <li className="p-3 rounded-xl border border-brand-accent/30 bg-brand-accent/5 space-y-2">
        <input
          value={front}
          onChange={(e) => setFront(e.target.value)}
          className="w-full text-sm font-medium bg-transparent border-b border-border/50 pb-1 outline-none"
          placeholder={t('flashcards.frontPlaceholder')}
          autoFocus
        />
        <textarea
          value={back}
          onChange={(e) => setBack(e.target.value)}
          rows={2}
          className="w-full text-xs text-muted-foreground bg-transparent outline-none resize-none"
          placeholder={t('flashcards.backPlaceholder')}
        />
        <div className="flex gap-2 pt-1">
          <button
            type="button"
            onClick={handleSave}
            disabled={saving || !front.trim() || !back.trim()}
            className="flex items-center gap-1 px-3 py-1.5 rounded-lg bg-brand-accent text-white text-[10px] font-bold disabled:opacity-50"
          >
            {saving ? <Loader2 size={10} className="animate-spin" /> : <Check size={10} />}
            {t('general.save') || 'Save'}
          </button>
          <button
            type="button"
            onClick={() => { setEditing(false); setFront(card.front); setBack(card.back) }}
            className="flex items-center gap-1 px-3 py-1.5 rounded-lg border border-border text-[10px] font-bold"
          >
            <X size={10} /> {t('general.cancel')}
          </button>
        </div>
      </li>
    )
  }

  return (
    <li className="p-3 rounded-xl border border-border/60 bg-paper/40 dark:bg-background/40 space-y-1.5">
      <div className="flex items-start justify-between gap-2">
        <p className="text-sm font-medium leading-snug line-clamp-2">{card.front}</p>
        <div className="flex shrink-0 items-center gap-1">
          {card.due && (
            <span className="px-1.5 py-0.5 rounded-full bg-red-500/10 text-red-600 text-[9px] font-bold uppercase">
              {t('flashcards.dueBadge')}
            </span>
          )}
          {card.mastered && (
            <span className="px-1.5 py-0.5 rounded-full bg-emerald-500/10 text-emerald-700 text-[9px] font-bold uppercase">
              {t('flashcards.masteredBadge')}
            </span>
          )}
          {/* Gap 7 — type badge */}
          <span className="px-1.5 py-0.5 rounded-full border border-border text-[9px] font-mono text-concrete">
            {TYPE_LABEL[card.type] ?? card.type}
          </span>
          {/* Gap 5 — edit button */}
          <button
            type="button"
            onClick={() => setEditing(true)}
            aria-label={t('flashcards.editCard')}
            className="p-1 rounded-md hover:bg-black/5 dark:hover:bg-white/5 text-concrete hover:text-foreground transition-colors"
          >
            <Pencil size={11} />
          </button>
          {/* Gap 5 — delete button */}
          {confirmDelete ? (
            <div className="flex items-center gap-1">
              <button
                type="button"
                onClick={handleDelete}
                disabled={deleting}
                className="px-2 py-0.5 rounded-md bg-red-500 text-white text-[9px] font-bold"
              >
                {deleting ? <Loader2 size={9} className="animate-spin inline" /> : t('general.confirm') || 'OK'}
              </button>
              <button
                type="button"
                onClick={() => setConfirmDelete(false)}
                className="px-2 py-0.5 rounded-md border border-border text-[9px] font-bold"
              >
                <X size={9} />
              </button>
            </div>
          ) : (
            <button
              type="button"
              onClick={() => setConfirmDelete(true)}
              aria-label={t('flashcards.deleteCard')}
              className="p-1 rounded-md hover:bg-red-500/10 text-concrete hover:text-red-500 transition-colors"
            >
              <Trash2 size={11} />
            </button>
          )}
        </div>
      </div>
      <p className="text-xs text-muted-foreground line-clamp-2">{card.back}</p>
    </li>
  )
}

export function RevisionView() {
  const { t } = useLanguage()
  const searchParams = useSearchParams()
  const initialDeckId = searchParams.get('deckId')

  const [tab, setTab] = useState<PageTab>('decks')
  const [decks, setDecks] = useState<DeckSummary[]>([])
  const [loadingDecks, setLoadingDecks] = useState(true)
  const [stats, setStats] = useState<StatsResponse | null>(null)
  const [loadingStats, setLoadingStats] = useState(false)

  const [activeDeckId, setActiveDeckId] = useState<string | null>(null)
  const [deckCards, setDeckCards] = useState<FlashcardItem[]>([])
  const [deckStats, setDeckStats] = useState({ total: 0, due: 0, mastered: 0 })
  const [loadingDeck, setLoadingDeck] = useState(false)

  // Gap 2 — review mode toggle
  const [reviewMode, setReviewMode] = useState<ReviewMode>('due')

  const [isSessionActive, setIsSessionActive] = useState(false)
  const [isSessionFinished, setIsSessionFinished] = useState(false)
  const [sessionCards, setSessionCards] = useState<FlashcardItem[]>([])
  const [currentIndex, setCurrentIndex] = useState(0)
  const [isFlipped, setIsFlipped] = useState(false)
  const [sessionGrades, setSessionGrades] = useState<Record<string, SessionGrade>>({})
  const [reviewing, setReviewing] = useState(false)
  const [highlightedGrade, setHighlightedGrade] = useState<SessionGrade | null>(null)

  // Gap 3 — session timer
  const [sessionStartTime, setSessionStartTime] = useState<number | null>(null)
  const [sessionDurationSeconds, setSessionDurationSeconds] = useState(0)
  const sessionTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)


  // Gap 8 — deck deletion state
  const [deletingDeckId, setDeletingDeckId] = useState<string | null>(null)
  const [confirmDeleteDeckId, setConfirmDeleteDeckId] = useState<string | null>(null)

  const initialSessionBootstrappedRef = useRef<string | null>(null)
  const deckCardRefs = useRef<Record<string, HTMLDivElement | null>>({})

  const [expandedDeckId, setExpandedDeckId] = useState<string | null>(null)
  const [loadingExpandedDeckId, setLoadingExpandedDeckId] = useState<string | null>(null)

  const loadDecks = useCallback(async () => {
    setLoadingDecks(true)
    try {
      const res = await fetch('/api/flashcards/decks')
      const data = await res.json()
      if (res.ok) setDecks(data.decks || [])
    } finally {
      setLoadingDecks(false)
    }
  }, [])

  const loadStats = useCallback(async () => {
    setLoadingStats(true)
    try {
      const res = await fetch('/api/flashcards/stats')
      const data = await res.json()
      if (res.ok) setStats(data)
    } finally {
      setLoadingStats(false)
    }
  }, [])

  const loadDeck = useCallback(async (deckId: string) => {
    setLoadingDeck(true)
    try {
      const res = await fetch(`/api/flashcards/decks/${deckId}`)
      const data = await res.json()
      if (!res.ok) {
        toast.error(data.errorKey ? t(data.errorKey) : (data.error || t('flashcards.loadDeckFailed')))
        return
      }
      setActiveDeckId(deckId)
      setDeckCards(data.deck.cards || [])
      setDeckStats(data.stats)
    } finally {
      setLoadingDeck(false)
    }
  }, [t])

  useEffect(() => {
    loadDecks()
  }, [loadDecks])

  useEffect(() => {
    if (tab === 'progress') loadStats()
  }, [tab, loadStats])

  // Gap 3 — session timer management
  const startTimer = useCallback(() => {
    const start = Date.now()
    setSessionStartTime(start)
    setSessionDurationSeconds(0)
    if (sessionTimerRef.current) clearInterval(sessionTimerRef.current)
    sessionTimerRef.current = setInterval(() => {
      setSessionDurationSeconds(Math.floor((Date.now() - start) / 1000))
    }, 1000)
  }, [])

  const stopTimer = useCallback(() => {
    if (sessionTimerRef.current) {
      clearInterval(sessionTimerRef.current)
      sessionTimerRef.current = null
    }
  }, [])

  useEffect(() => () => stopTimer(), [stopTimer])

  const startSession = useCallback((deckId: string, cardsInput: FlashcardItem[], mode: ReviewMode = reviewMode) => {
    if (cardsInput.length === 0) {
      void loadDeck(deckId)
      return
    }
    const shuffled = buildSessionQueue(cardsInput, mode === 'due')
    // Mode "due" mais aucune carte n'est due → afficher état "à jour" directement
    if (shuffled.length === 0) {
      setSessionCards([])
      setCurrentIndex(0)
      setIsFlipped(false)
      setSessionGrades({})
      setIsSessionActive(true)
      setIsSessionFinished(true)
      setActiveDeckId(deckId)
      return
    }
    setSessionCards(shuffled)
    setCurrentIndex(0)
    setIsFlipped(false)
    setSessionGrades({})
    setIsSessionActive(true)
    setIsSessionFinished(false)
    setActiveDeckId(deckId)
    startTimer()
  }, [loadDeck, reviewMode, startTimer])

  const toggleDeckDetails = useCallback(async (deckId: string) => {
    if (expandedDeckId === deckId) {
      setExpandedDeckId(null)
      return
    }

    setExpandedDeckId(deckId)
    setLoadingExpandedDeckId(deckId)

    try {
      const res = await fetch(`/api/flashcards/decks/${deckId}`)
      const data = await res.json()
      if (!res.ok) {
        toast.error(data.errorKey ? t(data.errorKey) : (data.error || t('flashcards.loadDeckFailed')))
        setExpandedDeckId(null)
        return
      }

      const cards: FlashcardItem[] = data.deck?.cards || []
      setActiveDeckId(deckId)
      setDeckCards(cards)
      setDeckStats(data.stats || { total: 0, due: 0, mastered: 0 })

      window.requestAnimationFrame(() => {
        deckCardRefs.current[deckId]?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
      })
    } catch {
      toast.error(t('flashcards.loadDeckFailed'))
      setExpandedDeckId(null)
    } finally {
      setLoadingExpandedDeckId(null)
    }
  }, [expandedDeckId, t])

  useEffect(() => {
    if (!initialDeckId) return
    if (initialSessionBootstrappedRef.current === initialDeckId) return

    let cancelled = false
    ;(async () => {
      const res = await fetch(`/api/flashcards/decks/${initialDeckId}`)
      const data = await res.json()
      if (cancelled || !res.ok) return

      const cards: FlashcardItem[] = data.deck?.cards || []
      initialSessionBootstrappedRef.current = initialDeckId
      setActiveDeckId(initialDeckId)
      setDeckCards(cards)
      setDeckStats(data.stats || { total: 0, due: 0, mastered: 0 })
      startSession(initialDeckId, cards)
    })()

    return () => {
      cancelled = true
    }
  }, [initialDeckId, startSession])

  const activeDeck = useMemo(
    () => decks.find((d) => d.id === activeDeckId),
    [decks, activeDeckId],
  )

  // Gap 3 — session summary stats
  const sessionSummary = useMemo(() => {
    const reviewed = Object.keys(sessionGrades).length
    const newMastered = Object.values(sessionGrades).filter((g) => g >= 3).length
    return { reviewed, newMastered }
  }, [sessionGrades])

  const sessionChartData = useMemo(() => {
    const counts = { 1: 0, 2: 0, 3: 0, 4: 0 }
    Object.values(sessionGrades).forEach((g) => { counts[g] += 1 })
    return [
      { label: t('flashcards.grade.hard'), value: counts[1] },
      { label: t('flashcards.grade.difficult'), value: counts[2] },
      { label: t('flashcards.grade.good'), value: counts[3] },
      { label: t('flashcards.grade.easy'), value: counts[4] },
    ]
  }, [sessionGrades, t])

  useEffect(() => {
    setHighlightedGrade(null)
  }, [currentIndex])

  const handleEvaluate = async (grade: SessionGrade) => {
    const card = sessionCards[currentIndex]
    if (!card || reviewing || highlightedGrade) return

    setHighlightedGrade(grade)
    setReviewing(true)
    setSessionGrades((prev) => ({ ...prev, [card.id]: grade }))

    const feedbackDelay = new Promise<void>((resolve) => {
      window.setTimeout(resolve, 650)
    })

    try {
      await Promise.all([
        fetch(`/api/flashcards/${card.id}/review`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ grade }),
        }),
        feedbackDelay,
      ])
    } catch {
      toast.error(t('flashcards.reviewFailed'))
    } finally {
      setReviewing(false)
    }

    if (currentIndex < sessionCards.length - 1) {
      setCurrentIndex((i) => i + 1)
      setIsFlipped(false)
      setHighlightedGrade(null)
    } else {
      stopTimer()
      setIsSessionFinished(true)
      setHighlightedGrade(null)
    }
  }

  useEffect(() => {
    if (!isSessionActive || isSessionFinished) return
    const onKey = (e: KeyboardEvent) => {
      if (e.code === 'Space') {
        e.preventDefault()
        setIsFlipped((f) => !f)
      } else if (isFlipped) {
        if (e.key === '1') handleEvaluate(1)
        if (e.key === '2') handleEvaluate(2)
        if (e.key === '3') handleEvaluate(3)
        if (e.key === '4') handleEvaluate(4)
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [isSessionActive, isSessionFinished, isFlipped, currentIndex, reviewing, highlightedGrade])

  const exitSession = () => {
    stopTimer()
    setIsSessionActive(false)
    setIsSessionFinished(false)
    if (activeDeckId) {
      loadDeck(activeDeckId)
      loadDecks()
    }
  }


  // Gap 8 — delete a deck
  const handleDeleteDeck = async (deckId: string) => {
    setDeletingDeckId(deckId)
    try {
      const res = await fetch(`/api/flashcards/decks/${deckId}`, { method: 'DELETE' })
      if (!res.ok) throw new Error()
      setDecks((prev) => prev.filter((d) => d.id !== deckId))
      if (activeDeckId === deckId) {
        setActiveDeckId(null)
        setDeckCards([])
      }
      if (expandedDeckId === deckId) setExpandedDeckId(null)
      toast.success(t('flashcards.deckDeleted'))
    } catch {
      toast.error(t('flashcards.deleteFailed'))
    } finally {
      setDeletingDeckId(null)
      setConfirmDeleteDeckId(null)
    }
  }

  const formatNextReview = (isoStr: string | null): string => {
    if (!isoStr) return ''
    const diff = new Date(isoStr).getTime() - Date.now()
    if (diff <= 0) return t('flashcards.dueToday')
    const days = Math.ceil(diff / (24 * 60 * 60 * 1000))
    return t('flashcards.nextReviewIn', { days })
  }

  const formatDue = (dueCount: number) => {
    if (dueCount > 0) return t('flashcards.dueCount', { count: dueCount })
    return t('flashcards.upToDate')
  }

  // Gap 5 — update card in local state after edit
  const handleCardSaved = useCallback((id: string, front: string, back: string) => {
    setDeckCards((prev) => prev.map((c) => c.id === id ? { ...c, front, back } : c))
  }, [])

  // Gap 5 — remove card from local state after delete
  const handleCardDeleted = useCallback((id: string) => {
    setDeckCards((prev) => prev.filter((c) => c.id !== id))
    setDeckStats((prev) => ({ ...prev, total: Math.max(0, prev.total - 1) }))
  }, [])

  return (
    <div className="h-full flex flex-col bg-memento-paper dark:bg-background overflow-y-auto">
      <div className="px-6 sm:px-10 py-5 flex items-center justify-between sticky top-0 bg-memento-paper/95 dark:bg-background/95 backdrop-blur-sm z-40 border-b border-border/40">
        <div className="flex items-center gap-3">
          {isSessionActive ? (
            <button
              type="button"
              onClick={exitSession}
              className="flex items-center gap-2 text-concrete hover:text-foreground transition-colors"
            >
              <ArrowLeft size={16} />
              <span className="text-xs font-bold uppercase tracking-widest">{t('flashcards.exitSession')}</span>
            </button>
          ) : (
            <div className="flex items-center gap-2">
              <GraduationCap className="text-brand-accent" size={20} />
              <h1 className="text-sm font-black tracking-widest uppercase">{t('nav.revision')}</h1>
            </div>
          )}
        </div>

        {!isSessionActive && (
          <div className="flex gap-1 p-1 rounded-lg bg-black/[0.04] dark:bg-white/[0.04]">
            {(['decks', 'progress'] as const).map((id) => (
              <button
                key={id}
                type="button"
                onClick={() => setTab(id)}
                className={cn(
                  'px-3 py-1.5 rounded-md text-[10px] font-bold uppercase tracking-wider transition-colors',
                  tab === id ? 'bg-white dark:bg-card shadow-sm text-brand-accent' : 'text-concrete',
                )}
              >
                {id === 'decks' ? t('flashcards.tabDecks') : t('flashcards.tabProgress')}
              </button>
            ))}
          </div>
        )}
      </div>

      <div className="flex-1 max-w-5xl mx-auto w-full p-6 sm:p-10">
        <AnimatePresence mode="wait">
          {isSessionActive && !isSessionFinished && sessionCards[currentIndex] && (
            <motion.div
              key="session"
              initial={{ opacity: 0, scale: 0.98 }}
              animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 0 }}
              className="max-w-2xl mx-auto flex flex-col items-center gap-8"
            >
              <div className="w-full flex items-center justify-between text-xs text-concrete">
                <button
                  type="button"
                  disabled={currentIndex === 0}
                  onClick={() => { setCurrentIndex((i) => i - 1); setIsFlipped(false) }}
                  className="flex items-center gap-1 disabled:opacity-30"
                >
                  <ChevronLeft size={16} /> {t('flashcards.previous')}
                </button>
                <div className="flex items-center gap-3">
                  {sessionStartTime !== null && (
                    <span className="font-mono text-[10px] text-concrete/60 flex items-center gap-1">
                      <Timer size={10} />
                      {formatDuration(sessionDurationSeconds)}
                    </span>
                  )}
                  <span className="font-mono font-bold px-3 py-1 rounded-full bg-black/[0.04] dark:bg-white/[0.06]">
                    {currentIndex + 1} / {sessionCards.length}
                  </span>
                </div>
                <button
                  type="button"
                  disabled={currentIndex >= sessionCards.length - 1}
                  onClick={() => { setCurrentIndex((i) => i + 1); setIsFlipped(false) }}
                  className="flex items-center gap-1 disabled:opacity-30"
                >
                  {t('flashcards.next')} <ChevronRight size={16} />
                </button>
              </div>

              <button
                type="button"
                onClick={() => {
                  if (highlightedGrade || reviewing) return
                  setIsFlipped((f) => !f)
                }}
                className={cn(
                  'w-full max-w-md min-h-[240px] [perspective:1000px] select-none',
                  highlightedGrade || reviewing ? 'cursor-default' : 'cursor-pointer',
                )}
              >
                <div
                  key={sessionCards[currentIndex].id}
                  className={cn(
                    'relative w-full min-h-[240px] transition-transform duration-500 [transform-style:preserve-3d]',
                    isFlipped && '[transform:rotateY(180deg)]',
                  )}
                >
                  <div className="absolute inset-0 [backface-visibility:hidden] rounded-2xl border border-border bg-card p-8 flex flex-col shadow-sm">
                    <span className="text-[10px] uppercase tracking-widest text-concrete mb-4">{t('flashcards.front')}</span>
                    <p className="flex-1 flex items-center justify-center text-center text-lg font-serif font-semibold">
                      {sessionCards[currentIndex].front}
                    </p>
                    <span className="text-[10px] text-concrete/60 text-center">{t('flashcards.tapToFlip')}</span>
                  </div>
                  <div
                    className={cn(
                      'absolute inset-0 [backface-visibility:hidden] [transform:rotateY(180deg)] rounded-2xl border-2 p-8 flex flex-col shadow-md transition-all duration-300',
                      !highlightedGrade && 'border-brand-accent/30 bg-brand-accent/5',
                      highlightedGrade === 1 && 'border-red-500 bg-red-500/[0.07] shadow-lg shadow-red-500/10',
                      highlightedGrade === 2 && 'border-amber-500 bg-amber-500/[0.07] shadow-lg shadow-amber-500/10',
                      highlightedGrade === 3 && 'border-emerald-500 bg-emerald-500/[0.07] shadow-lg shadow-emerald-500/10',
                      highlightedGrade === 4 && 'border-brand-accent bg-brand-accent/10 shadow-lg shadow-brand-accent/10',
                    )}
                  >
                    <span className="text-[10px] uppercase tracking-widest text-brand-accent mb-4">{t('flashcards.back')}</span>
                    <p className="flex-1 flex items-center justify-center text-center text-sm leading-relaxed overflow-y-auto">
                      {sessionCards[currentIndex].back}
                    </p>
                  </div>
                </div>
              </button>

              {isFlipped && (
                <div className="w-full max-w-md space-y-3">
                  <AnimatePresence mode="wait">
                    {highlightedGrade ? (
                      <motion.div
                        key="grade-confirmed"
                        initial={{ opacity: 0, y: 8, scale: 0.95 }}
                        animate={{ opacity: 1, y: 0, scale: 1 }}
                        exit={{ opacity: 0, y: -4 }}
                        transition={{ type: 'spring', stiffness: 400, damping: 28 }}
                        className={cn(
                          'flex items-center justify-center gap-2 py-2.5 px-4 rounded-xl border text-xs font-bold',
                          GRADE_OPTIONS.find((o) => o.grade === highlightedGrade)?.selected,
                          GRADE_OPTIONS.find((o) => o.grade === highlightedGrade)?.ring,
                          'ring-2',
                        )}
                      >
                        <Check size={14} className="shrink-0" />
                        {t('flashcards.gradeSelected', {
                          label: t(`flashcards.grade.${['hard', 'difficult', 'good', 'easy'][highlightedGrade - 1]}`),
                        })}
                      </motion.div>
                    ) : (
                      <motion.p
                        key="grade-hint"
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1 }}
                        exit={{ opacity: 0 }}
                        className="text-center text-[11px] text-concrete font-medium"
                      >
                        {t('flashcards.ratePrompt')}
                      </motion.p>
                    )}
                  </AnimatePresence>

                  <div className="grid grid-cols-2 sm:grid-cols-4 gap-2">
                    {GRADE_OPTIONS.map(({ grade, idle, selected, ring }) => {
                      const label = t(`flashcards.grade.${['hard', 'difficult', 'good', 'easy'][grade - 1]}`)
                      const isSelected = highlightedGrade === grade
                      const isDimmed = highlightedGrade !== null && !isSelected

                      return (
                        <motion.button
                          key={grade}
                          type="button"
                          disabled={reviewing}
                          onClick={() => handleEvaluate(grade)}
                          animate={{
                            scale: isSelected ? 1.06 : isDimmed ? 0.92 : 1,
                            opacity: isDimmed ? 0.35 : 1,
                          }}
                          transition={{ type: 'spring', stiffness: 420, damping: 26 }}
                          className={cn(
                            'py-3 px-2 rounded-xl border text-[10px] font-bold uppercase tracking-wide',
                            'flex flex-col items-center justify-center gap-1 min-h-[52px]',
                            isSelected ? cn(selected, 'ring-2', ring) : idle,
                          )}
                        >
                          {isSelected && (
                            <motion.span
                              initial={{ scale: 0, opacity: 0 }}
                              animate={{ scale: 1, opacity: 1 }}
                              transition={{ type: 'spring', stiffness: 500, damping: 22 }}
                            >
                              <Check size={14} strokeWidth={3} />
                            </motion.span>
                          )}
                          <span>{label}</span>
                        </motion.button>
                      )
                    })}
                  </div>
                </div>
              )}
            </motion.div>
          )}

          {/* Gap 3 — enriched session summary */}
          {isSessionFinished && (
            <motion.div
              key="finished"
              initial={{ opacity: 0, y: 10 }}
              animate={{ opacity: 1, y: 0 }}
              className="max-w-lg mx-auto text-center space-y-6"
            >
              <GraduationCap size={40} className="mx-auto text-brand-accent" />
              <h2 className="text-2xl font-serif font-bold">{t('flashcards.sessionComplete')}</h2>

              {/* Stats summary row */}
              <div className="grid grid-cols-3 gap-3">
                <div className="p-3 rounded-xl border border-border bg-card/50 text-center">
                  <p className="text-[10px] uppercase tracking-widest text-concrete mb-1">{t('flashcards.sessionReviewed')}</p>
                  <p className="text-2xl font-serif font-bold">{sessionSummary.reviewed}</p>
                </div>
                <div className="p-3 rounded-xl border border-emerald-500/20 bg-emerald-500/5 text-center">
                  <p className="text-[10px] uppercase tracking-widest text-concrete mb-1">{t('flashcards.sessionNewMastered')}</p>
                  <p className="text-2xl font-serif font-bold text-emerald-600">{sessionSummary.newMastered}</p>
                </div>
                <div className="p-3 rounded-xl border border-border bg-card/50 text-center">
                  <p className="text-[10px] uppercase tracking-widest text-concrete mb-1 flex items-center justify-center gap-1">
                    <Clock size={9} />{t('flashcards.sessionDuration')}
                  </p>
                  <p className="text-2xl font-serif font-bold font-mono">{formatDuration(sessionDurationSeconds)}</p>
                </div>
              </div>

              <div className="h-48">
                <NoteChart type="bar" data={sessionChartData} height={180} />
              </div>
              <button
                type="button"
                onClick={exitSession}
                className="px-6 py-2.5 rounded-xl bg-brand-accent text-white text-xs font-bold uppercase tracking-wider"
              >
                {t('flashcards.backToDecks')}
              </button>
            </motion.div>
          )}

          {!isSessionActive && tab === 'decks' && (
            <motion.div key="decks" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-8">
              {activeDeckId && deckCards.length > 0 && (
                <div className="p-5 rounded-2xl border border-brand-accent/25 bg-brand-accent/5 space-y-3">
                  <h3 className="font-serif font-semibold text-lg">{activeDeck?.name || t('flashcards.activeDeck')}</h3>
                  <div className="flex flex-wrap gap-3 text-xs text-concrete">
                    <span>{t('flashcards.statTotal', { count: deckStats.total })}</span>
                    <span>{t('flashcards.statDue', { count: deckStats.due })}</span>
                    <span>{t('flashcards.statMastered', { count: deckStats.mastered })}</span>
                  </div>

                  {/* Gap 2 — review mode toggle */}
                  <div className="flex gap-1 p-1 rounded-lg bg-black/[0.04] dark:bg-white/[0.04] w-fit">
                    {(['due', 'all'] as const).map((mode) => (
                      <button
                        key={mode}
                        type="button"
                        onClick={() => setReviewMode(mode)}
                        className={cn(
                          'px-3 py-1.5 rounded-md text-[10px] font-bold uppercase tracking-wider transition-colors',
                          reviewMode === mode ? 'bg-white dark:bg-card shadow-sm text-brand-accent' : 'text-concrete',
                        )}
                      >
                        {mode === 'due' ? t('flashcards.reviewModeDue') : t('flashcards.reviewModeAll')}
                      </button>
                    ))}
                  </div>

                  <button
                    type="button"
                    onClick={() => startSession(activeDeckId, deckCards, reviewMode)}
                    disabled={loadingDeck}
                    className="px-4 py-2 rounded-lg bg-brand-accent text-white text-xs font-bold uppercase tracking-wider flex items-center gap-2"
                  >
                    {loadingDeck ? <Loader2 size={14} className="animate-spin" /> : <GraduationCap size={14} />}
                    {t('flashcards.startReview')}
                  </button>
                </div>
              )}


              {loadingDecks ? (
                <div className="flex justify-center py-16"><Loader2 className="animate-spin text-concrete" /></div>
              ) : decks.length === 0 ? (
                <div className="text-center py-16 border border-dashed border-border rounded-2xl space-y-3">
                  <GraduationCap size={32} className="mx-auto text-concrete/40" />
                  <p className="text-sm text-concrete">{t('flashcards.emptyDecks')}</p>
                  <p className="text-xs text-concrete/60 max-w-md mx-auto">{t('flashcards.emptyDecksHint')}</p>
                </div>
              ) : (
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                  {decks.map((deck) => {
                    const isExpanded = expandedDeckId === deck.id
                    const isLoadingDetails = loadingExpandedDeckId === deck.id
                    const showDetails = isExpanded && activeDeckId === deck.id
                    const isConfirmingDelete = confirmDeleteDeckId === deck.id
                    const isDeletingThis = deletingDeckId === deck.id

                    return (
                      <div
                        key={deck.id}
                        ref={(el) => {
                          deckCardRefs.current[deck.id] = el
                        }}
                        className={cn(
                          'p-5 rounded-2xl border bg-card/50 transition-colors flex flex-col gap-4 group',
                          isExpanded
                            ? 'border-brand-accent/40 ring-1 ring-brand-accent/15 shadow-sm'
                            : 'border-border/60 hover:border-brand-accent/30',
                        )}
                      >
                        <div>
                          <div className="flex items-start justify-between gap-2">
                            <div className="space-y-1 min-w-0">
                              <h3 className="font-serif font-semibold truncate group-hover:text-brand-accent transition-colors">{deck.name}</h3>
                              <p className="text-xs text-concrete flex items-center gap-1">
                                <Layers size={12} />
                                {t('flashcards.cardCountLabel', { count: deck.totalCards })}
                              </p>
                            </div>

                            {/* Cercle SVG de progression (maîtrise) — comme dans le prototype */}
                            {deck.totalCards > 0 && (() => {
                              const masteryScore = deck.masteredCount / deck.totalCards
                              const r = 19
                              const circ = 2 * Math.PI * r
                              return (
                                <div className="relative w-12 h-12 flex items-center justify-center shrink-0">
                                  <svg className="w-full h-full -rotate-90">
                                    <circle cx="24" cy="24" r={r} stroke="currentColor" strokeWidth="2" className="text-border" fill="transparent" />
                                    <circle cx="24" cy="24" r={r} stroke="currentColor" strokeWidth="3" className="text-emerald-500" fill="transparent"
                                      strokeDasharray={circ}
                                      strokeDashoffset={circ * (1 - masteryScore)}
                                    />
                                  </svg>
                                  <span className="absolute text-[10px] font-mono font-black text-emerald-600 dark:text-emerald-400">
                                    {Math.round(masteryScore * 100)}%
                                  </span>
                                </div>
                              )
                            })()}

                            {/* Bouton supprimer */}
                            {isConfirmingDelete ? (
                              <div className="flex items-center gap-1 shrink-0">
                                <button
                                  type="button"
                                  onClick={() => handleDeleteDeck(deck.id)}
                                  disabled={isDeletingThis}
                                  className="px-2 py-0.5 rounded-md bg-red-500 text-white text-[9px] font-bold flex items-center gap-0.5"
                                >
                                  {isDeletingThis ? <Loader2 size={9} className="animate-spin" /> : null}
                                  {t('general.confirm') || 'OK'}
                                </button>
                                <button
                                  type="button"
                                  onClick={() => setConfirmDeleteDeckId(null)}
                                  className="p-1 rounded-md border border-border text-[9px]"
                                >
                                  <X size={10} />
                                </button>
                              </div>
                            ) : (
                              <button
                                type="button"
                                onClick={() => setConfirmDeleteDeckId(deck.id)}
                                aria-label={t('flashcards.deleteDeck')}
                                className="p-1 rounded-md hover:bg-red-500/10 text-concrete hover:text-red-500 transition-colors shrink-0"
                              >
                                <Trash2 size={13} />
                              </button>
                            )}
                          </div>
                          {/* Notebook badge */}
                          {deck.notebookName && (
                            <div className="mt-1">
                              <span className="flex items-center gap-1 text-[10px] text-concrete/70 border border-border/50 rounded-full px-2 py-0.5 w-fit">
                                <BookMarked size={9} />
                                {deck.notebookName}
                              </span>
                            </div>
                          )}
                        </div>
                        <div className="flex flex-wrap gap-2 text-[10px]">
                          {deck.dueCount > 0 ? (
                            <span className="px-2.5 py-1 rounded-full bg-amber-500/10 text-amber-600 dark:text-amber-400 font-bold border border-amber-500/15 animate-pulse">
                              {formatDue(deck.dueCount)}
                            </span>
                          ) : (
                            <span className="px-2.5 py-1 rounded-full bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 font-bold border border-emerald-500/15">
                              {t('flashcards.upToDate')}
                            </span>
                          )}
                          {deck.nextReviewAt && (
                            <span className="px-2.5 py-1 rounded-full border border-border flex items-center gap-1 font-mono text-concrete">
                              <Calendar size={10} />
                              {t('flashcards.nextReviewLabel')} : {formatNextReview(deck.nextReviewAt)}
                            </span>
                          )}
                        </div>
                        <div className="flex gap-2 pt-2 border-t border-border/40">
                          <button
                            type="button"
                            onClick={() => void toggleDeckDetails(deck.id)}
                            className={cn(
                              'flex-1 py-2 text-[10px] font-bold uppercase tracking-wider border rounded-lg flex items-center justify-center gap-1 transition-colors',
                              isExpanded
                                ? 'border-brand-accent/40 bg-brand-accent/10 text-brand-accent'
                                : 'border-border hover:bg-black/[0.03] dark:hover:bg-white/[0.04]',
                            )}
                          >
                            {isLoadingDetails ? (
                              <Loader2 size={12} className="animate-spin" />
                            ) : (
                              <ChevronDown
                                size={12}
                                className={cn('transition-transform', isExpanded && 'rotate-180')}
                              />
                            )}
                            {isExpanded ? t('flashcards.hideDeck') : t('flashcards.viewDeck')}
                          </button>
                          <button
                            type="button"
                            onClick={async () => {
                              setLoadingDeck(true)
                              try {
                                const res = await fetch(`/api/flashcards/decks/${deck.id}`)
                                const data = await res.json()
                                if (res.ok) {
                                  setActiveDeckId(deck.id)
                                  setDeckCards(data.deck.cards || [])
                                  setDeckStats(data.stats)
                                  setExpandedDeckId(null)
                                  startSession(deck.id, data.deck.cards || [], reviewMode)
                                }
                              } finally {
                                setLoadingDeck(false)
                              }
                            }}
                            className="flex-1 py-2 text-[10px] font-bold uppercase tracking-wider bg-brand-accent text-white rounded-lg flex items-center justify-center gap-1"
                          >
                            <GraduationCap size={12} />
                            {t('flashcards.review')}
                          </button>
                        </div>

                        <AnimatePresence initial={false}>
                          {isExpanded && (
                            <motion.div
                              key={`deck-details-${deck.id}`}
                              initial={{ height: 0, opacity: 0 }}
                              animate={{ height: 'auto', opacity: 1 }}
                              exit={{ height: 0, opacity: 0 }}
                              transition={{ duration: 0.25, ease: 'easeOut' }}
                              className="overflow-hidden"
                            >
                              <div className="pt-1 space-y-3 border-t border-border/40">
                                {isLoadingDetails ? (
                                  <div className="flex justify-center py-6">
                                    <Loader2 size={18} className="animate-spin text-concrete" />
                                  </div>
                                ) : showDetails && deckCards.length === 0 ? (
                                  <p className="text-xs text-concrete py-4 text-center">
                                    {t('flashcards.deckCardsEmpty')}
                                  </p>
                                ) : showDetails ? (
                                  <>
                                    <div className="flex flex-wrap gap-2 text-[10px] text-concrete pt-2">
                                      <span>{t('flashcards.statTotal', { count: deckStats.total })}</span>
                                      <span>{t('flashcards.statDue', { count: deckStats.due })}</span>
                                      <span>{t('flashcards.statMastered', { count: deckStats.mastered })}</span>
                                    </div>
                                    {/* Gap 2 — mode toggle inside deck details too */}
                                    <div className="flex gap-1 p-1 rounded-lg bg-black/[0.04] dark:bg-white/[0.04] w-fit">
                                      {(['due', 'all'] as const).map((mode) => (
                                        <button
                                          key={mode}
                                          type="button"
                                          onClick={() => setReviewMode(mode)}
                                          className={cn(
                                            'px-3 py-1.5 rounded-md text-[10px] font-bold uppercase tracking-wider transition-colors',
                                            reviewMode === mode ? 'bg-white dark:bg-card shadow-sm text-brand-accent' : 'text-concrete',
                                          )}
                                        >
                                          {mode === 'due' ? t('flashcards.reviewModeDue') : t('flashcards.reviewModeAll')}
                                        </button>
                                      ))}
                                    </div>
                                    <ul className="max-h-64 overflow-y-auto custom-scrollbar space-y-2 pr-1">
                                      {/* Gap 5, 7 — CardEditRow with edit/delete + type badge */}
                                      {deckCards.map((card) => (
                                        <CardEditRow
                                          key={card.id}
                                          card={card}
                                          onSaved={handleCardSaved}
                                          onDeleted={handleCardDeleted}
                                        />
                                      ))}
                                    </ul>
                                    <button
                                      type="button"
                                      onClick={() => startSession(deck.id, deckCards, reviewMode)}
                                      className="w-full py-2.5 rounded-lg bg-brand-accent text-white text-[10px] font-bold uppercase tracking-wider flex items-center justify-center gap-1.5"
                                    >
                                      <GraduationCap size={12} />
                                      {t('flashcards.startReview')}
                                    </button>
                                  </>
                                ) : null}
                              </div>
                            </motion.div>
                          )}
                        </AnimatePresence>
                      </div>
                    )
                  })}
                </div>
              )}
            </motion.div>
          )}

          {!isSessionActive && tab === 'progress' && (
            <motion.div key="progress" initial={{ opacity: 0 }} animate={{ opacity: 1 }} className="space-y-8">
              {loadingStats ? (
                <div className="flex justify-center py-16"><Loader2 className="animate-spin text-concrete" /></div>
              ) : stats ? (
                <>
                  <div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
                    <div className="p-4 rounded-xl border border-border bg-card/50">
                      <p className="text-[10px] uppercase tracking-widest text-concrete">{t('flashcards.retentionRate')}</p>
                      <p className="text-3xl font-serif font-bold mt-1">{stats.retentionRate}%</p>
                    </div>
                    <div className="p-4 rounded-xl border border-border bg-card/50 sm:col-span-2">
                      <p className="text-[10px] uppercase tracking-widest text-concrete mb-2 flex items-center gap-1">
                        <BarChart3 size={12} /> {t('flashcards.retentionCurve')}
                      </p>
                      <RetentionCurve data={stats.retentionByWeek} />
                    </div>
                  </div>

                  <RevisionHeatmap data={stats.heatmap} />

                  {stats.difficultCards.length > 0 && (
                    <div className="space-y-3">
                      <div className="flex items-center justify-between">
                        <h3 className="text-sm font-bold uppercase tracking-widest text-concrete flex items-center gap-2">
                          <BookOpen size={14} /> {t('flashcards.difficultCards')}
                        </h3>
                        <span className="text-[10px] text-concrete/60">{stats.difficultCards.length} cartes</span>
                      </div>
                      <ul className="space-y-1.5 max-h-80 overflow-y-auto custom-scrollbar pr-1">
                        {stats.difficultCards.map((c) => (
                          <li key={c.id} className="p-3 rounded-xl border border-border/60 flex items-center justify-between gap-3 group hover:border-brand-accent/30 transition-colors">
                            <div className="min-w-0 flex-1">
                              <p className="text-sm truncate">{c.front}</p>
                              <p className="text-[10px] text-concrete/60 mt-0.5">{c.deckName}</p>
                            </div>
                            <div className="flex items-center gap-2 shrink-0">
                              <span className="text-[10px] font-mono text-concrete">EF {c.easinessFactor.toFixed(2)}</span>
                              <button
                                type="button"
                                onClick={async () => {
                                  setLoadingDeck(true)
                                  setTab('decks')
                                  try {
                                    const res = await fetch(`/api/flashcards/decks/${c.deckId}`)
                                    const data = await res.json()
                                    if (res.ok) {
                                      setActiveDeckId(c.deckId)
                                      setDeckCards(data.deck.cards || [])
                                      setDeckStats(data.stats)
                                      startSession(c.deckId, data.deck.cards || [], reviewMode)
                                    }
                                  } finally {
                                    setLoadingDeck(false)
                                  }
                                }}
                                className="opacity-0 group-hover:opacity-100 transition-opacity px-2 py-1 rounded-lg bg-brand-accent text-white text-[9px] font-bold uppercase tracking-wider flex items-center gap-1"
                              >
                                <GraduationCap size={10} />
                                {t('flashcards.review')}
                              </button>
                            </div>
                          </li>
                        ))}
                      </ul>
                    </div>
                  )}
                </>
              ) : null}
            </motion.div>
          )}
        </AnimatePresence>
      </div>
    </div>
  )
}
