import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import { motion } from 'framer-motion'
import { Lightbulb, Maximize2, Minimize2, RotateCcw } from 'lucide-react'
import { knowledgeAreas } from '@/data'
import { InputArea } from '@/components/practice/InputArea'
import { CelebrationAnimation } from '@/components/practice/CelebrationAnimation'
import { useLongPress } from '@/hooks/useLongPress'
import { announceToScreenReader, normalizeAnswer } from '@/utils/practice'
import {
  generateTailoringPracticeItems,
  type TailoringPracticeItem,
} from '@/utils/tailoringPractice'
import { useAppStore } from '@/stores/useAppStore'

type CharStatus = 'pending' | 'correct' | 'error'

const STORAGE_KEY = 'knowledge-areas-tailoring-practice-progress'

interface AnswerOverlayState {
  itemId: string
  answer: string
  expiresAt: number
}

interface FactorTitleCellProps {
  item: TailoringPracticeItem
  isPracticeMode: boolean
  isAnswered: boolean
  isCurrent: boolean
  showAnswer: string | null
  onLongPress: (itemId: string) => void
  onLongPressEnd: () => void
  onClick: (itemId: string) => void
}

function FactorTitleCell({
  item,
  isPracticeMode,
  isAnswered,
  isCurrent,
  showAnswer,
  onLongPress,
  onLongPressEnd,
  onClick,
}: FactorTitleCellProps) {
  const longPressHandlers = useLongPress(item.id, {
    onLongPress,
    onLongPressEnd,
  })

  if (!isPracticeMode) {
    return (
      <div className="px-4 py-4">
        <div className="flex items-start gap-3">
          <span className="inline-flex h-7 min-w-7 items-center justify-center rounded-full bg-amber-100 px-2 text-xs font-semibold text-amber-700 dark:bg-amber-900/40 dark:text-amber-300">
            {item.factorIndex + 1}
          </span>
          <div className="min-w-0 flex-1">
            <div className="text-sm font-medium leading-6 text-gray-900 dark:text-gray-100">
              {item.title}
            </div>
            <p className="mt-2 text-sm leading-7 text-gray-700 dark:text-gray-200">
              {item.description}
            </p>
          </div>
        </div>
      </div>
    )
  }

  return (
    <button
      type="button"
      onClick={() => onClick(item.id)}
      tabIndex={isCurrent ? 0 : -1}
      aria-current={isCurrent ? 'step' : undefined}
      aria-label={`裁剪因素：${item.title}`}
      className={clsx(
        'relative w-full px-4 py-4 text-left transition-all duration-200 focus:outline-none',
        isCurrent
          ? 'bg-indigo-50 dark:bg-indigo-900/20 ring-2 ring-inset ring-indigo-500'
          : 'bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700/60',
      )}
      {...longPressHandlers}
    >
      <div className="flex min-h-[96px] items-start gap-3">
        <span className="inline-flex h-7 min-w-7 items-center justify-center rounded-full bg-amber-100 px-2 text-xs font-semibold text-amber-700 dark:bg-amber-900/40 dark:text-amber-300">
          {item.factorIndex + 1}
        </span>

        <div className="min-w-0 flex-1">
          {isAnswered ? (
            <div className="text-sm font-medium leading-6 text-gray-900 dark:text-gray-100">
              {item.title}
            </div>
          ) : (
            <div className="flex h-6 items-center">
              <span
                className={clsx(
                  'block h-3 rounded-full bg-gray-200 dark:bg-gray-600',
                  isCurrent && 'bg-indigo-200 dark:bg-indigo-700/70'
                )}
                style={{ width: `${Math.min(Math.max(item.title.length, 4) * 0.8, 8)}rem` }}
              />
            </div>
          )}

          <p className="mt-2 text-sm leading-7 text-gray-700 dark:text-gray-200">
            {item.description}
          </p>
        </div>
      </div>

      {showAnswer && (
        <div className="absolute inset-0 z-10 flex items-center justify-center rounded bg-black/80 px-4">
          <span className="text-center text-sm font-medium text-white">
            {showAnswer}
          </span>
        </div>
      )}
    </button>
  )
}

export default function KnowledgeAreasTailoringPage() {
  const setSidebarOpen = useAppStore((s) => s.setSidebarOpen)
  const [practiceItems] = useState<TailoringPracticeItem[]>(() => generateTailoringPracticeItems())
  const practiceItemMap = useMemo(
    () => new Map(practiceItems.map((item) => [item.id, item])),
    [practiceItems]
  )
  const sortedKnowledgeAreas = useMemo(
    () => [...knowledgeAreas].sort((a, b) => a.order - b.order),
    []
  )

  const groupedKnowledgeAreas = useMemo(
    () =>
      sortedKnowledgeAreas.map((knowledgeArea) => ({
        ...knowledgeArea,
        items: practiceItems.filter((item) => item.knowledgeAreaId === knowledgeArea.id),
      })),
    [practiceItems, sortedKnowledgeAreas]
  )

  const loadProgress = useCallback(() => {
    const validIds = new Set(practiceItems.map((item) => item.id))

    try {
      const saved = localStorage.getItem(STORAGE_KEY)
      if (!saved) {
        return {
          answeredItems: new Map<string, boolean>(),
          currentItemId: practiceItems[0]?.id ?? null,
        }
      }

      const parsed = JSON.parse(saved)
      const answeredEntries = Array.isArray(parsed.answeredItems)
        ? parsed.answeredItems.filter(
            (entry: unknown) =>
              Array.isArray(entry) && entry[1] === true && typeof entry[0] === 'string' && validIds.has(entry[0])
          )
        : []

      return {
        answeredItems: new Map<string, boolean>(answeredEntries),
        currentItemId:
          typeof parsed.currentItemId === 'string' && validIds.has(parsed.currentItemId)
            ? parsed.currentItemId
            : practiceItems[0]?.id ?? null,
      }
    } catch (error) {
      console.error('加载裁剪因素练习进度失败:', error)
      return {
        answeredItems: new Map<string, boolean>(),
        currentItemId: practiceItems[0]?.id ?? null,
      }
    }
  }, [practiceItems])

  const [isPracticeMode, setIsPracticeMode] = useState(false)
  const [isFullScreen, setIsFullScreen] = useState(false)
  const [answeredItems, setAnsweredItems] = useState<Map<string, boolean>>(
    () => loadProgress().answeredItems
  )
  const [currentItemId, setCurrentItemId] = useState<string | null>(
    () => loadProgress().currentItemId
  )
  const [userInput, setUserInput] = useState<string[]>([])
  const [charStatuses, setCharStatuses] = useState<CharStatus[]>([])
  const [isComposing, setIsComposing] = useState(false)
  const isComposingRef = useRef(false)
  const latestInputRef = useRef<string[]>([])
  const [lastErrorTimestamp, setLastErrorTimestamp] = useState<number | null>(null)
  const [showAnswerForItem, setShowAnswerForItem] = useState<AnswerOverlayState | null>(null)
  const [inputLocked, setInputLocked] = useState(false)
  const [showCelebration, setShowCelebration] = useState(false)

  const currentItem = currentItemId ? practiceItemMap.get(currentItemId) ?? null : null
  const answeredCount = answeredItems.size
  const totalCount = practiceItems.length

  useEffect(() => {
    latestInputRef.current = userInput
  }, [userInput])

  useEffect(() => {
    try {
      localStorage.setItem(
        STORAGE_KEY,
        JSON.stringify({
          answeredItems: Array.from(answeredItems.entries()),
          currentItemId,
        })
      )
    } catch (error) {
      console.error('保存裁剪因素练习进度失败:', error)
    }
  }, [answeredItems, currentItemId])

  useEffect(() => {
    if (!isPracticeMode) {
      setShowAnswerForItem(null)
      setInputLocked(false)
      setIsComposing(false)
      isComposingRef.current = false
      return
    }

    if (!currentItem && practiceItems[0]) {
      setCurrentItemId(practiceItems[0].id)
      return
    }

    if (!currentItem) return

    setUserInput(new Array(currentItem.title.length).fill(''))
    setCharStatuses(new Array(currentItem.title.length).fill('pending'))
  }, [currentItem, isPracticeMode, practiceItems])

  const restoreFocus = useCallback(() => {
    setTimeout(() => {
      const inputs = document.querySelectorAll('.practice-input-area input')
      const firstEmptyInput = Array.from(inputs).find(
        (input) => !(input as HTMLInputElement).value
      ) as HTMLInputElement | undefined

      if (firstEmptyInput) {
        firstEmptyInput.focus()
      } else {
        ;(inputs[0] as HTMLInputElement | undefined)?.focus()
      }
    }, 100)
  }, [])

  const switchToItem = useCallback((item: TailoringPracticeItem) => {
    setCurrentItemId(item.id)
    setUserInput(new Array(item.title.length).fill(''))
    setCharStatuses(new Array(item.title.length).fill('pending'))
    setLastErrorTimestamp(null)

    requestAnimationFrame(() => {
      const element = document.querySelector(`[data-factor-id="${item.id}"]`) as HTMLElement | null
      element?.scrollIntoView({ behavior: 'smooth', block: 'center' })
    })

    setTimeout(() => {
      const firstInput = document.querySelector('.practice-input-area input') as HTMLInputElement | null
      firstInput?.focus()
    }, 150)
  }, [])

  const moveToNextItem = useCallback(() => {
    const currentIndex = practiceItems.findIndex((item) => item.id === currentItemId)
    if (currentIndex === -1 || currentIndex === practiceItems.length - 1) return
    switchToItem(practiceItems[currentIndex + 1])
  }, [currentItemId, practiceItems, switchToItem])

  const moveToPrevItem = useCallback(() => {
    const currentIndex = practiceItems.findIndex((item) => item.id === currentItemId)
    if (currentIndex <= 0) return
    switchToItem(practiceItems[currentIndex - 1])
  }, [currentItemId, practiceItems, switchToItem])

  const validateInput = useCallback(
    (input: string[]) => {
      if (!currentItem || !currentItemId) return

      const originalAnswer = currentItem.title
      const normalizedInput = normalizeAnswer(input.join(''), false)
      const normalizedAnswer = currentItem.normalizedAnswer
      const normalizeChar = (char: string) => normalizeAnswer(char, false) || char

      const nextStatuses = input.map((char, index) => {
        if (!char) return 'pending' as CharStatus
        const expectedChar = originalAnswer[index] || ''
        if (!expectedChar) return 'error' as CharStatus
        return normalizeChar(char) === normalizeChar(expectedChar)
          ? ('correct' as CharStatus)
          : ('error' as CharStatus)
      })
      setCharStatuses(nextStatuses)

      const isComplete = input.every((char) => char !== '') && input.length === originalAnswer.length
      const isCorrect = isComplete && normalizedInput === normalizedAnswer

      if (isCorrect) {
        const alreadyAnswered = answeredItems.get(currentItemId) === true
        const nextAnsweredCount = alreadyAnswered ? answeredItems.size : answeredItems.size + 1

        setAnsweredItems((prev) => new Map(prev).set(currentItemId, true))

        if (nextAnsweredCount === practiceItems.length) {
          setTimeout(() => {
            setShowCelebration(true)
          }, 300)
          return
        }

        setTimeout(() => {
          moveToNextItem()
        }, 300)
      } else if (isComplete) {
        setLastErrorTimestamp(Date.now())
      }
    },
    [answeredItems, currentItem, currentItemId, moveToNextItem, practiceItems.length]
  )

  const handleInputChange = useCallback(
    (newInput: string[]) => {
      latestInputRef.current = newInput
      setUserInput(newInput)

      if (isComposingRef.current) return

      validateInput(newInput)
    },
    [validateInput]
  )

  const handleCompositionStart = useCallback((_index: number) => {
    isComposingRef.current = true
    setIsComposing(true)
  }, [])

  const handleCompositionEnd = useCallback(
    (index: number, value: string) => {
      isComposingRef.current = false
      setIsComposing(false)

      requestAnimationFrame(() => {
        const currentInput = latestInputRef.current
        const nextInput = [...currentInput]

        if (value) {
          const chars = value.split('')
          for (let i = 0; i < chars.length && index + i < nextInput.length; i += 1) {
            nextInput[index + i] = chars[i]
          }
        } else {
          nextInput[index] = ''
        }

        latestInputRef.current = nextInput
        setUserInput(nextInput)
        validateInput(nextInput)
      })
    },
    [validateInput]
  )

  const handlePaste = useCallback(
    (e: React.ClipboardEvent) => {
      e.preventDefault()
      if (!currentItem) return

      const pastedText = e.clipboardData.getData('text')
      const nextInput = new Array(currentItem.title.length).fill('')
      const chars = pastedText.split('')

      for (let i = 0; i < Math.min(chars.length, currentItem.title.length); i += 1) {
        nextInput[i] = chars[i]
      }

      handleInputChange(nextInput)
    },
    [currentItem, handleInputChange]
  )

  const handleLongPress = useCallback(
    (itemId: string) => {
      const item = practiceItemMap.get(itemId)
      if (!item) return

      setShowAnswerForItem({
        itemId,
        answer: item.title,
        expiresAt: Date.now() + 3000,
      })
      setInputLocked(true)
      announceToScreenReader('答案已显示')
    },
    [practiceItemMap]
  )

  const handleLongPressEnd = useCallback(() => {
    if (!showAnswerForItem) return

    setShowAnswerForItem(null)
    setInputLocked(false)
    announceToScreenReader('答案已隐藏')
    restoreFocus()
  }, [restoreFocus, showAnswerForItem])

  useEffect(() => {
    if (!showAnswerForItem) return

    const remaining = showAnswerForItem.expiresAt - Date.now()
    if (remaining <= 0) {
      setShowAnswerForItem(null)
      setInputLocked(false)
      restoreFocus()
      return
    }

    const timer = setTimeout(() => {
      setShowAnswerForItem(null)
      setInputLocked(false)
      announceToScreenReader('答案已自动隐藏')
      restoreFocus()
    }, remaining)

    return () => clearTimeout(timer)
  }, [restoreFocus, showAnswerForItem])

  const handleFactorClick = useCallback(
    (itemId: string) => {
      const item = practiceItemMap.get(itemId)
      if (!item) return
      switchToItem(item)
    },
    [practiceItemMap, switchToItem]
  )

  const toggleFullScreen = useCallback(() => {
    if (!isFullScreen) {
      setSidebarOpen(false)
    }
    setIsFullScreen((prev) => !prev)
  }, [isFullScreen, setSidebarOpen])

  const handleResetProgress = useCallback(() => {
    if (!window.confirm('确定要清除当前练习进度吗？')) return

    setAnsweredItems(new Map())
    setCurrentItemId(practiceItems[0]?.id ?? null)
    setUserInput([])
    setCharStatuses([])
    setLastErrorTimestamp(null)
    localStorage.removeItem(STORAGE_KEY)
    announceToScreenReader('练习进度已重置')
  }, [practiceItems])

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      const lowerKey = e.key.toLowerCase()

      if (e.ctrlKey && lowerKey === 'h') {
        e.preventDefault()
        if (isPracticeMode && currentItemId && !showAnswerForItem) {
          handleLongPress(currentItemId)
        }
        return
      }

      if (e.key === 'Escape') {
        if (showAnswerForItem) {
          handleLongPressEnd()
          return
        }

        if (isFullScreen) {
          setIsFullScreen(false)
          return
        }

        if (isPracticeMode) {
          setUserInput((prev) => new Array(prev.length).fill(''))
          setCharStatuses((prev) => new Array(prev.length).fill('pending'))
        }
        return
      }

      if (!isPracticeMode) return

      if (e.key === 'Tab') {
        e.preventDefault()
        if (e.shiftKey) {
          moveToPrevItem()
        } else {
          moveToNextItem()
        }
      }
    }

    const handleKeyUp = (e: KeyboardEvent) => {
      const lowerKey = e.key.toLowerCase()
      if ((lowerKey === 'control' || lowerKey === 'h') && showAnswerForItem) {
        handleLongPressEnd()
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    window.addEventListener('keyup', handleKeyUp)
    return () => {
      window.removeEventListener('keydown', handleKeyDown)
      window.removeEventListener('keyup', handleKeyUp)
    }
  }, [
    currentItemId,
    handleLongPress,
    handleLongPressEnd,
    isFullScreen,
    isPracticeMode,
    moveToNextItem,
    moveToPrevItem,
    showAnswerForItem,
  ])

  const renderToolbar = (compact = false) => (
    <>
      <div className={clsx('flex items-center justify-between gap-4', compact ? 'px-4 py-3' : 'px-5 py-4')}>
        <div>
          <div className="flex items-center gap-2 text-sm font-medium text-gray-900 dark:text-white">
            <Lightbulb className="h-4 w-4 text-amber-500" />
            <span>10 个知识领域 · {totalCount} 项敏捷裁剪因素</span>
          </div>
          <p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
            结合知识领域查看裁剪关注点，并在练习模式中完成因素标题记忆。
          </p>
        </div>

        <div className="flex items-center gap-2">
          {isPracticeMode && (
            <button
              type="button"
              onClick={handleResetProgress}
              className="inline-flex items-center gap-1 rounded-lg border border-gray-200 px-3 py-2 text-sm text-gray-600 transition-colors hover:text-red-600 dark:border-gray-700 dark:text-gray-300 dark:hover:text-red-400"
            >
              <RotateCcw className="h-4 w-4" />
              清除进度
            </button>
          )}

          <div className="flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-700">
            <button
              type="button"
              onClick={() => setIsPracticeMode(false)}
              className={clsx(
                'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
                !isPracticeMode
                  ? 'bg-white text-gray-900 shadow-sm dark:bg-gray-600 dark:text-white'
                  : 'text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-white'
              )}
            >
              查看
            </button>
            <button
              type="button"
              onClick={() => setIsPracticeMode(true)}
              className={clsx(
                'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
                isPracticeMode
                  ? 'bg-white text-gray-900 shadow-sm dark:bg-gray-600 dark:text-white'
                  : 'text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-white'
              )}
            >
              练习
            </button>
          </div>

          <button
            type="button"
            onClick={toggleFullScreen}
            className="inline-flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-700"
          >
            {isFullScreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
            {isFullScreen ? '退出全屏' : '全屏查看'}
          </button>
        </div>
      </div>

      {isPracticeMode && (
        <div className={clsx('border-t border-gray-100 dark:border-gray-700', compact ? 'px-4 py-3' : 'px-5 py-3')}>
          <div className="mb-2 flex items-center justify-between text-sm text-gray-600 dark:text-gray-300">
            <span>练习进度：{answeredCount} / {totalCount}</span>
            {currentItem && (
              <span className="text-xs text-gray-500 dark:text-gray-400">
                当前：{currentItem.knowledgeAreaName} · 第 {currentItem.factorIndex + 1} 项
              </span>
            )}
          </div>
          <div className="h-2 w-full rounded-full bg-gray-200 dark:bg-gray-700">
            <motion.div
              className="h-2 rounded-full bg-indigo-500"
              initial={{ width: 0 }}
              animate={{ width: `${(answeredCount / totalCount) * 100}%` }}
              transition={{ duration: 0.3 }}
            />
          </div>
        </div>
      )}
    </>
  )

  return (
    <div
      className={clsx(
        isFullScreen
          ? 'fixed inset-0 z-50 flex flex-col bg-gray-50 dark:bg-gray-900'
          : 'flex min-h-[calc(100vh-7rem)] flex-col gap-6'
      )}
    >
      {isFullScreen && (
        <style>{`
          .tailoring-no-scrollbar::-webkit-scrollbar {
            display: none;
          }
          .tailoring-no-scrollbar {
            -ms-overflow-style: none;
            scrollbar-width: none;
          }
        `}</style>
      )}

      {!isFullScreen && (
        <div className="flex items-end justify-between gap-4">
          <div>
            <h1 className="text-2xl font-bold text-gray-900 dark:text-white">知识领域敏捷裁剪因素</h1>
          </div>
        </div>
      )}

      <div
        className={clsx(
          'overflow-hidden border border-gray-100 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800',
          isFullScreen
            ? 'flex min-h-0 flex-1 flex-col border-0 rounded-none shadow-none'
            : 'flex min-h-0 flex-1 flex-col rounded-2xl'
        )}
      >
        {renderToolbar(isFullScreen)}

        <div
          className={clsx(
            'flex-1 overflow-y-auto overflow-x-hidden',
            isFullScreen && 'tailoring-no-scrollbar'
          )}
        >
          <table className="w-full table-fixed border-collapse">
            <colgroup>
              <col className="w-[12rem] sm:w-[14rem] lg:w-[16rem]" />
              <col />
            </colgroup>
            <thead>
              <tr>
                <th className="sticky left-0 top-0 z-20 border border-gray-200 bg-gray-100 px-4 py-3 text-left text-sm font-semibold text-gray-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300">
                  知识领域
                </th>
                <th className="sticky top-0 z-10 border border-gray-200 bg-gray-100 px-4 py-3 text-left text-sm font-semibold text-gray-700 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300">
                  裁剪因素与说明
                </th>
              </tr>
            </thead>
            <tbody>
              {groupedKnowledgeAreas.map((knowledgeArea) => {
                if (knowledgeArea.items.length === 0) return null

                const isCurrentKnowledgeArea = currentItem?.knowledgeAreaId === knowledgeArea.id

                return knowledgeArea.items.map((item, itemIndex) => {
                  const isAnswered = answeredItems.get(item.id) === true
                  const isCurrent = isPracticeMode && currentItemId === item.id
                  const isShowingAnswer = showAnswerForItem?.itemId === item.id ? showAnswerForItem.answer : null

                  return (
                    <tr
                      key={item.id}
                      data-factor-id={item.id}
                      className={clsx(isCurrent && 'bg-indigo-50/40 dark:bg-indigo-900/10')}
                    >
                      {itemIndex === 0 && (
                        <td
                          rowSpan={knowledgeArea.items.length}
                          className="sticky left-0 z-10 border border-gray-200 px-4 py-4 align-top dark:border-gray-700"
                          style={{
                            backgroundColor: `${knowledgeArea.color}16`,
                            borderLeftWidth: 4,
                            borderLeftColor: knowledgeArea.color,
                          }}
                        >
                          <div className="space-y-3">
                            <div className="flex items-center gap-3">
                              <div
                                className="flex h-10 w-10 items-center justify-center rounded-lg text-sm font-bold text-white"
                                style={{ backgroundColor: knowledgeArea.color }}
                              >
                                {knowledgeArea.order}
                              </div>
                              <div>
                                <h3 className="font-semibold text-gray-900 dark:text-white">
                                  {knowledgeArea.name}
                                </h3>
                                <p className="text-xs text-gray-500 dark:text-gray-400">
                                  {knowledgeArea.items.length} 项裁剪因素
                                </p>
                              </div>
                            </div>
                            <p className="text-sm leading-6 text-gray-600 dark:text-gray-300">
                              {knowledgeArea.description}
                            </p>
                            {isPracticeMode && isCurrentKnowledgeArea && (
                              <div className="rounded-lg bg-white/70 px-3 py-2 text-xs text-gray-600 dark:bg-gray-900/20 dark:text-gray-300">
                                当前正在练习该知识领域中的第 {currentItem ? currentItem.factorIndex + 1 : 1} 项
                              </div>
                            )}
                          </div>
                        </td>
                      )}
                      <td className="border border-gray-200 p-0 align-top dark:border-gray-700">
                        <div
                          className={clsx(
                            'overflow-hidden bg-white dark:bg-gray-800',
                            isCurrent && 'bg-indigo-50/30 dark:bg-indigo-900/10'
                          )}
                        >
                          <FactorTitleCell
                            item={item}
                            isPracticeMode={isPracticeMode}
                            isAnswered={isAnswered}
                            isCurrent={isCurrent}
                            showAnswer={isShowingAnswer}
                            onLongPress={handleLongPress}
                            onLongPressEnd={handleLongPressEnd}
                            onClick={handleFactorClick}
                          />
                        </div>
                      </td>
                    </tr>
                  )
                })
              })}
            </tbody>
          </table>
        </div>

      </div>

      {isPracticeMode && currentItem && (
        <div className="sticky bottom-0 z-10 border-t border-gray-200 bg-white/60 pb-8 backdrop-blur-md dark:border-gray-700 dark:bg-gray-800/60">
          <div className="px-6">
            <div className="border-b border-gray-200/50 py-3 dark:border-gray-700/50">
              <div className="flex items-center justify-center gap-3">
                <InputArea
                  userInput={userInput}
                  charStatuses={charStatuses}
                  isComposing={isComposing}
                  inputLocked={inputLocked}
                  lastErrorTimestamp={lastErrorTimestamp}
                  onInputChange={handleInputChange}
                  onCompositionStart={handleCompositionStart}
                  onCompositionEnd={handleCompositionEnd}
                  onPaste={handlePaste}
                />
                <button
                  type="button"
                  onClick={() => currentItemId && handleLongPress(currentItemId)}
                  className="p-2 text-gray-500 transition-colors hover:text-indigo-600 dark:text-gray-400 dark:hover:text-indigo-400"
                  title="查看答案（长按表格中的因素标题也可以）"
                >
                  <svg className="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
                  </svg>
                </button>
              </div>
            </div>

            <div className="grid gap-3 py-3 md:grid-cols-[220px,1fr] md:items-start">
              <div>
                <div className="text-sm font-semibold text-gray-900 dark:text-white">
                  {currentItem.knowledgeAreaName}
                </div>
                <div className="mt-1 text-xs text-gray-500 dark:text-gray-400">
                  第 {currentItem.factorIndex + 1} 项 · 长按标题或 Ctrl+H 查看答案 · Tab 切换
                </div>
              </div>
              <p className="text-sm leading-7 text-gray-700 dark:text-gray-200">
                {currentItem.description}
              </p>
            </div>
          </div>
        </div>
      )}

      <div id="aria-live-region" className="sr-only" aria-live="polite" aria-atomic="true" />

      {showCelebration && <CelebrationAnimation onComplete={() => setShowCelebration(false)} />}
    </div>
  )
}
