import { useParams, Link, useLocation, useNavigate } from 'react-router-dom'
import { motion } from 'framer-motion'
import {
  ArrowLeft,
  ArrowRight,
  FileText,
  Wrench,
  FileOutput,
  LayoutGrid,
  Eye,
  EyeOff,
  Info,
  Check,
} from 'lucide-react'
import { getProcessDetail, processes } from '@/data'
import { useState, useEffect, useMemo, useCallback, useRef } from 'react'
import { InputArea } from '@/components/practice/InputArea'
import { ProficientInputArea } from '@/components/practice/ProficientInputArea'
import { normalizeAnswer } from '@/utils/practice'
import { CelebrationAnimation } from '@/components/practice/CelebrationAnimation'
import { useAppStore } from '@/stores/useAppStore'

type IttoSection = 'inputs' | 'tools' | 'outputs'
type CharStatus = 'pending' | 'correct' | 'error'

interface PracticeItem {
  id: string
  section: IttoSection
  name: string
  normalizedAnswer: string
  originalData: any
}

const STORAGE_KEY = 'ittoview:process-detail:itto-visibility'
const SECTION_ORDER: IttoSection[] = ['inputs', 'tools', 'outputs']
const SECTION_LABELS: Record<IttoSection, string> = {
  inputs: '输入',
  tools: '工具与技术',
  outputs: '输出',
}
const SECTION_THEME: Record<IttoSection, { header: string; icon: string; accent: string; button: string }> = {
  inputs: {
    header: 'bg-blue-50 dark:bg-blue-900/30 border-blue-100 dark:border-blue-800',
    icon: 'text-blue-600 dark:text-blue-400',
    accent: 'text-blue-900 dark:text-blue-100',
    button: 'text-blue-700 dark:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-900/50',
  },
  tools: {
    header: 'bg-amber-50 dark:bg-amber-900/30 border-amber-100 dark:border-amber-800',
    icon: 'text-amber-600 dark:text-amber-400',
    accent: 'text-amber-900 dark:text-amber-100',
    button: 'text-amber-700 dark:text-amber-300 hover:bg-amber-100 dark:hover:bg-amber-900/50',
  },
  outputs: {
    header: 'bg-emerald-50 dark:bg-emerald-900/30 border-emerald-100 dark:border-emerald-800',
    icon: 'text-emerald-600 dark:text-emerald-400',
    accent: 'text-emerald-900 dark:text-emerald-100',
    button: 'text-emerald-700 dark:text-emerald-300 hover:bg-emerald-100 dark:hover:bg-emerald-900/50',
  },
}

function getSectionIcon(section: IttoSection) {
  if (section === 'inputs') return FileText
  if (section === 'tools') return Wrench
  return FileOutput
}

function getFirstAvailableSection(itemsBySection: Record<IttoSection, PracticeItem[]>): IttoSection {
  return SECTION_ORDER.find((section) => itemsBySection[section].length > 0) ?? 'inputs'
}

function getNextSection(
  currentSection: IttoSection,
  itemsBySection: Record<IttoSection, PracticeItem[]>,
  answeredItems: Set<string>
): IttoSection | null {
  const currentIndex = SECTION_ORDER.indexOf(currentSection)
  for (let index = currentIndex + 1; index < SECTION_ORDER.length; index += 1) {
    const nextSection = SECTION_ORDER[index]
    const remaining = itemsBySection[nextSection].some((item) => !answeredItems.has(item.id))
    if (remaining) return nextSection
  }
  return null
}

export function ProcessDetailPage() {
  const { id } = useParams()
  const location = useLocation()
  const navigate = useNavigate()
  const { practiceMode } = useAppStore()
  const processDetail = useMemo(() => (id ? getProcessDetail(id) : null), [id])

  const [visible, setVisible] = useState<Record<IttoSection, boolean>>(() => {
    const defaultVisible = { inputs: true, tools: true, outputs: true }
    try {
      const raw = localStorage.getItem(STORAGE_KEY)
      if (!raw) return defaultVisible
      const parsed = JSON.parse(raw)
      if (typeof parsed !== 'object' || parsed === null) return defaultVisible
      return {
        inputs: typeof parsed.inputs === 'boolean' ? parsed.inputs : true,
        tools: typeof parsed.tools === 'boolean' ? parsed.tools : true,
        outputs: typeof parsed.outputs === 'boolean' ? parsed.outputs : true,
      }
    } catch {
      return defaultVisible
    }
  })

  useEffect(() => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(visible))
    } catch (error) {
      console.warn('无法保存 ITTO 显示状态:', error)
    }
  }, [visible])

  const toggleSection = (key: IttoSection) => {
    setVisible((prev) => ({ ...prev, [key]: !prev[key] }))
  }

  const allVisible = Object.values(visible).every(Boolean)
  const toggleAll = () => {
    const newState = !allVisible
    setVisible({ inputs: newState, tools: newState, outputs: newState })
  }

  const practiceItems = useMemo<PracticeItem[]>(() => {
    if (!processDetail) return []
    const buildItems = (details: any[] | undefined, section: IttoSection): PracticeItem[] => {
      if (!details) return []
      return details.map((detail: any, index: number) => {
        const name: string = detail?.name || detail?.id || `项${index + 1}`
        return {
          id: `${section}-${detail?.id || index}`,
          section,
          name,
          normalizedAnswer: normalizeAnswer(name, false),
          originalData: detail,
        }
      })
    }

    return [
      ...buildItems(processDetail.inputDetails, 'inputs'),
      ...buildItems(processDetail.toolDetails, 'tools'),
      ...buildItems(processDetail.outputDetails, 'outputs'),
    ]
  }, [processDetail])

  const itemsBySection = useMemo<Record<IttoSection, PracticeItem[]>>(
    () => ({
      inputs: practiceItems.filter((item) => item.section === 'inputs'),
      tools: practiceItems.filter((item) => item.section === 'tools'),
      outputs: practiceItems.filter((item) => item.section === 'outputs'),
    }),
    [practiceItems]
  )

  const [isPracticeMode, setIsPracticeMode] = useState(false)
  const [answeredItems, setAnsweredItems] = useState<Set<string>>(new Set())
  const [currentPracticeId, setCurrentPracticeId] = useState<string | null>(null)
  const [userInput, setUserInput] = useState<string[]>([])
  const [charStatuses, setCharStatuses] = useState<CharStatus[]>([])
  const [isComposing, setIsComposing] = useState(false)
  const isComposingRef = useRef(false)
  const latestInputRef = useRef<string[]>([])

  const [currentSection, setCurrentSection] = useState<IttoSection>('inputs')
  const [proficientInput, setProficientInput] = useState('')
  const [proficientHasError, setProficientHasError] = useState(false)

  const [inputLocked, setInputLocked] = useState(false)
  const [lastErrorTimestamp, setLastErrorTimestamp] = useState<number | null>(null)
  const [showAnswer, setShowAnswer] = useState(false)
  const longPressTimerRef = useRef<number | null>(null)
  const autoAdvanceTimerRef = useRef<number | null>(null)
  const answerRevealTimerRef = useRef<number | null>(null)
  const debounceTimerRef = useRef<number | null>(null)

  const [showCelebration, setShowCelebration] = useState(false)

  const currentPracticeItem = useMemo(
    () => practiceItems.find((item) => item.id === currentPracticeId) ?? null,
    [practiceItems, currentPracticeId]
  )
  const currentPracticeIndex = practiceItems.findIndex((item) => item.id === currentPracticeId)

  const currentSectionItems = itemsBySection[currentSection]
  const currentSectionRemainingItems = currentSectionItems.filter((item) => !answeredItems.has(item.id))
  const completedCount = answeredItems.size

  const clearLongPressTimer = useCallback(() => {
    if (longPressTimerRef.current !== null) {
      window.clearTimeout(longPressTimerRef.current)
      longPressTimerRef.current = null
    }
  }, [])

  const clearAutoAdvanceTimer = useCallback(() => {
    if (autoAdvanceTimerRef.current !== null) {
      window.clearTimeout(autoAdvanceTimerRef.current)
      autoAdvanceTimerRef.current = null
    }
  }, [])

  const clearAnswerRevealTimer = useCallback(() => {
    if (answerRevealTimerRef.current !== null) {
      window.clearTimeout(answerRevealTimerRef.current)
      answerRevealTimerRef.current = null
    }
  }, [])

  const clearDebounceTimer = useCallback(() => {
    if (debounceTimerRef.current !== null) {
      window.clearTimeout(debounceTimerRef.current)
      debounceTimerRef.current = null
    }
  }, [])

  useEffect(() => {
    return () => {
      clearLongPressTimer()
      clearAutoAdvanceTimer()
      clearAnswerRevealTimer()
      clearDebounceTimer()
    }
  }, [clearLongPressTimer, clearAutoAdvanceTimer, clearAnswerRevealTimer, clearDebounceTimer])

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

  const hideAnswerAndUnlock = useCallback(() => {
    clearAnswerRevealTimer()
    setShowAnswer(false)
    setInputLocked(false)
  }, [clearAnswerRevealTimer])

  const exitPractice = useCallback(() => {
    clearAutoAdvanceTimer()
    clearLongPressTimer()
    clearAnswerRevealTimer()
    clearDebounceTimer()
    setIsPracticeMode(false)
    setAnsweredItems(new Set())
    setCurrentPracticeId(null)
    setUserInput([])
    setCharStatuses([])
    setIsComposing(false)
    isComposingRef.current = false
    setCurrentSection(getFirstAvailableSection(itemsBySection))
    setProficientInput('')
    setProficientHasError(false)
    setLastErrorTimestamp(null)
    setShowAnswer(false)
    setInputLocked(false)
  }, [
    clearAutoAdvanceTimer,
    clearLongPressTimer,
    clearAnswerRevealTimer,
    clearDebounceTimer,
    itemsBySection,
  ])

  const finishPractice = useCallback(() => {
    clearAutoAdvanceTimer()
    autoAdvanceTimerRef.current = window.setTimeout(() => {
      setShowCelebration(true)
      window.setTimeout(() => {
        setShowCelebration(false)
        exitPractice()
      }, 2000)
    }, 500)
  }, [clearAutoAdvanceTimer, exitPractice])

  const startPractice = useCallback(() => {
    if (practiceItems.length === 0) return
    clearAutoAdvanceTimer()
    clearAnswerRevealTimer()
    clearDebounceTimer()
    setIsPracticeMode(true)
    setAnsweredItems(new Set())
    setShowAnswer(false)
    setInputLocked(false)
    setLastErrorTimestamp(null)

    if (practiceMode === 'proficient') {
      setCurrentSection(getFirstAvailableSection(itemsBySection))
      setCurrentPracticeId(null)
      setProficientInput('')
      setProficientHasError(false)
    } else {
      setCurrentPracticeId(practiceItems[0].id)
      setProficientInput('')
      setProficientHasError(false)
    }
  }, [
    practiceItems,
    practiceMode,
    itemsBySection,
    clearAutoAdvanceTimer,
    clearAnswerRevealTimer,
    clearDebounceTimer,
  ])

  const currentPracticeNameLength = currentPracticeItem?.name.length ?? 0
  useEffect(() => {
    if (!isPracticeMode || practiceMode !== 'standard' || !currentPracticeId || currentPracticeNameLength === 0) return
    setUserInput(new Array(currentPracticeNameLength).fill(''))
    setCharStatuses(new Array(currentPracticeNameLength).fill('pending'))
    setLastErrorTimestamp(null)
    setShowAnswer(false)
    setInputLocked(false)
    setTimeout(() => {
      const firstInput = document.querySelector('.practice-input-area input') as HTMLInputElement | null
      firstInput?.focus()
    }, 150)
  }, [isPracticeMode, practiceMode, currentPracticeId, currentPracticeNameLength])

  useEffect(() => {
    exitPractice()
  }, [id, practiceMode, exitPractice])

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

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.ctrlKey && event.key.toLowerCase() === 'h') {
        event.preventDefault()
        clearLongPressTimer()
        clearDebounceTimer()
        clearAnswerRevealTimer()

        if (practiceMode === 'proficient') {
          setProficientInput('')
          setProficientHasError(false)
        }

        setShowAnswer(true)
        setInputLocked(true)
      }
    }

    const handleKeyUp = (event: KeyboardEvent) => {
      if (event.key === 'Control' || event.key.toLowerCase() === 'h') {
        hideAnswerAndUnlock()
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    window.addEventListener('keyup', handleKeyUp)

    return () => {
      window.removeEventListener('keydown', handleKeyDown)
      window.removeEventListener('keyup', handleKeyUp)
    }
  }, [
    isPracticeMode,
    practiceMode,
    hideAnswerAndUnlock,
    clearLongPressTimer,
    clearDebounceTimer,
    clearAnswerRevealTimer,
  ])

  const revealAnswersForThreeSeconds = useCallback(() => {
    if (!isPracticeMode) return
    clearLongPressTimer()
    clearDebounceTimer()
    clearAnswerRevealTimer()

    if (practiceMode === 'proficient') {
      setProficientInput('')
      setProficientHasError(false)
    }

    setShowAnswer(true)
    setInputLocked(true)
    answerRevealTimerRef.current = window.setTimeout(() => {
      setShowAnswer(false)
      setInputLocked(false)
      const input = document.querySelector('.practice-input-area input') as HTMLInputElement | null
      input?.focus()
    }, 3000)
  }, [
    isPracticeMode,
    practiceMode,
    clearLongPressTimer,
    clearDebounceTimer,
    clearAnswerRevealTimer,
  ])

  const validateInput = useCallback(
    (input: string[]) => {
      if (!currentPracticeItem) return
      const originalAnswer = currentPracticeItem.name
      const normalizedInput = normalizeAnswer(input.join(''), false)
      const normalizedAnswer = currentPracticeItem.normalizedAnswer
      const normalizeChar = (char: string) => normalizeAnswer(char, false) || char

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

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

      if (isCorrect) {
        const nextAnsweredItems = new Set(answeredItems)
        nextAnsweredItems.add(currentPracticeItem.id)
        setAnsweredItems(nextAnsweredItems)
        clearAutoAdvanceTimer()
        if (currentPracticeIndex === practiceItems.length - 1) {
          finishPractice()
        } else {
          autoAdvanceTimerRef.current = window.setTimeout(() => {
            setCurrentPracticeId(practiceItems[currentPracticeIndex + 1].id)
          }, 300)
        }
      } else if (isComplete) {
        setLastErrorTimestamp(Date.now())
      }
    },
    [answeredItems, currentPracticeItem, currentPracticeIndex, practiceItems, clearAutoAdvanceTimer, finishPractice]
  )

  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)
    clearDebounceTimer()
  }, [clearDebounceTimer])

  const handleCompositionEnd = useCallback(
    (indexOrValue: number | string, maybeValue?: string) => {
      isComposingRef.current = false
      setIsComposing(false)

      if (practiceMode === 'proficient') {
        const nextValue = typeof indexOrValue === 'string' ? indexOrValue : maybeValue ?? ''
        setProficientInput(nextValue)
        return
      }

      const index = indexOrValue as number
      const value = maybeValue ?? ''
      requestAnimationFrame(() => {
        const current = latestInputRef.current
        const newInput = [...current]
        if (value) {
          value.split('').forEach((char, offset) => {
            if (index + offset < newInput.length) newInput[index + offset] = char
          })
        } else {
          newInput[index] = ''
        }
        latestInputRef.current = newInput
        setUserInput(newInput)
        validateInput(newInput)
      })
    },
    [practiceMode, validateInput]
  )

  const handlePaste = useCallback(
    (e: React.ClipboardEvent) => {
      if (!currentPracticeItem) return
      e.preventDefault()
      const text = e.clipboardData.getData('text')
      const targetLength = currentPracticeItem.name.length
      const newInput = new Array(targetLength).fill('')
      text.split('').forEach((char, index) => {
        if (index < targetLength) newInput[index] = char
      })
      handleInputChange(newInput)
    },
    [currentPracticeItem, handleInputChange]
  )

  const submitProficientAnswer = useCallback((rawValue: string) => {
    const normalizedValue = normalizeAnswer(rawValue, false)
    if (!normalizedValue || inputLocked) return

    const targetItems = itemsBySection[currentSection]
    const matchedItem = targetItems.find(
      (item) => !answeredItems.has(item.id) && item.normalizedAnswer === normalizedValue
    )

    if (!matchedItem) {
      setProficientHasError(true)
      return
    }

    const nextAnsweredItems = new Set(answeredItems)
    nextAnsweredItems.add(matchedItem.id)
    setAnsweredItems(nextAnsweredItems)
    setProficientInput('')
    setProficientHasError(false)

    const currentSectionDone = itemsBySection[currentSection].every((item) => nextAnsweredItems.has(item.id))
    const allDone = practiceItems.every((item) => nextAnsweredItems.has(item.id))

    if (allDone) {
      finishPractice()
      return
    }

    if (currentSectionDone) {
      const nextSection = getNextSection(currentSection, itemsBySection, nextAnsweredItems)
      if (nextSection) {
        setCurrentSection(nextSection)
      }
      return
    }
  }, [answeredItems, currentSection, inputLocked, itemsBySection, practiceItems, finishPractice])

  useEffect(() => {
    if (!isPracticeMode || practiceMode !== 'proficient' || isComposing || inputLocked) return
    clearDebounceTimer()
    if (!normalizeAnswer(proficientInput, false)) return

    debounceTimerRef.current = window.setTimeout(() => {
      submitProficientAnswer(proficientInput)
    }, 800)

    return clearDebounceTimer
  }, [
    isPracticeMode,
    practiceMode,
    proficientInput,
    isComposing,
    inputLocked,
    submitProficientAnswer,
    clearDebounceTimer,
  ])

  if (!processDetail) {
    return (
      <div className="flex flex-col items-center justify-center py-20">
        <h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4">未找到该过程</h2>
        <Link to="/knowledge-areas" className="text-indigo-600 dark:text-indigo-400 hover:underline">
          返回知识领域
        </Link>
      </div>
    )
  }

  const ka = processDetail.knowledgeArea
  const pg = processDetail.processGroup
  const purpose = (processDetail as any).purpose

  const currentIndex = processes.findIndex((process) => process.id === id)
  const prevProcess = currentIndex > 0 ? processes[currentIndex - 1] : null
  const nextProcess = currentIndex < processes.length - 1 ? processes[currentIndex + 1] : null
  const fromMatrix = location.state?.from === 'matrix'
  const practiceModeLabel = practiceMode === 'proficient' ? '熟练模式' : '标准模式'

  return (
    <div className={`space-y-4 ${isPracticeMode ? 'pb-44' : ''}`}>
      <div className="flex items-center gap-3 text-sm">
        {fromMatrix && (
          <button
            onClick={() => navigate('/process-matrix')}
            className="flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors font-medium"
          >
            <LayoutGrid size={14} />
            返回矩阵
          </button>
        )}
        <nav className="flex items-center gap-1.5 text-gray-500 dark:text-gray-400">
          <Link to="/knowledge-areas" className="hover:text-indigo-600 dark:hover:text-indigo-400">知识领域</Link>
          <span>/</span>
          {ka && (
            <>
              <Link to={`/knowledge-areas/${ka.id}`} className="hover:text-indigo-600 dark:hover:text-indigo-400">{ka.name}</Link>
              <span>/</span>
            </>
          )}
          <span className="text-gray-900 dark:text-white">{processDetail.name}</span>
        </nav>
      </div>

      <motion.div
        initial={{ opacity: 0, y: -10 }}
        animate={{ opacity: 1, y: 0 }}
        className="rounded-xl p-4 bg-white dark:bg-gray-800 shadow-sm border border-gray-100 dark:border-gray-700"
      >
        <div className="flex items-center gap-3">
          <div
            className="flex h-12 w-12 items-center justify-center rounded-lg text-white font-bold text-lg shrink-0"
            style={{ backgroundColor: ka?.color || '#6366F1' }}
          >
            {processDetail.code}
          </div>
          <div className="flex-1 min-w-0">
            <h1 className="text-xl font-bold text-gray-900 dark:text-white truncate">{processDetail.name}</h1>
            <p className="text-sm text-gray-500 dark:text-gray-400">{processDetail.nameEn}</p>
          </div>
          <div className="flex items-center gap-2 shrink-0 flex-wrap justify-end">
            {ka && (
              <span className="px-2.5 py-1 rounded-full text-xs font-medium text-white" style={{ backgroundColor: ka.color }}>
                {ka.name}
              </span>
            )}
            {pg && (
              <span className="px-2.5 py-1 rounded-full text-xs font-medium text-white" style={{ backgroundColor: pg.color }}>
                {pg.name}
              </span>
            )}
            <span className="px-2.5 py-1 rounded-full text-xs font-medium bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-200">
              {practiceModeLabel}
            </span>
            <button
              type="button"
              onClick={isPracticeMode ? exitPractice : startPractice}
              disabled={practiceItems.length === 0}
              className={`px-3 py-1.5 rounded-lg text-xs font-semibold transition-colors disabled:opacity-40 disabled:cursor-not-allowed ${
                isPracticeMode
                  ? 'bg-red-50 text-red-600 hover:bg-red-100 dark:bg-red-900/30 dark:text-red-300 dark:hover:bg-red-900/50'
                  : 'bg-indigo-50 text-indigo-600 hover:bg-indigo-100 dark:bg-indigo-900/30 dark:text-indigo-300 dark:hover:bg-indigo-900/50'
              }`}
            >
              {isPracticeMode ? '退出练习' : '开始练习'}
            </button>
          </div>
        </div>
      </motion.div>

      {purpose && (
        <motion.div
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: 0.05 }}
          className="bg-indigo-50 dark:bg-indigo-900/20 rounded-xl p-4 border border-indigo-100 dark:border-indigo-800"
        >
          <div className="flex items-center gap-2 mb-2">
            <Info size={16} className="text-indigo-600 dark:text-indigo-400 shrink-0" />
            <h3 className="text-sm font-semibold text-indigo-900 dark:text-indigo-100">主要作用</h3>
          </div>
          <p className="text-sm text-indigo-800 dark:text-indigo-200 leading-relaxed">{purpose}</p>
        </motion.div>
      )}

      {!isPracticeMode && (
        <motion.div
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          transition={{ delay: 0.08 }}
          className="flex justify-end"
        >
          <button
            type="button"
            onClick={toggleAll}
            aria-label={allVisible ? '隐藏所有 ITTO 内容' : '显示所有 ITTO 内容'}
            aria-pressed={allVisible}
            className="flex items-center gap-2 px-3 py-1.5 rounded-lg bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors text-sm font-medium"
          >
            {allVisible ? <EyeOff size={16} /> : <Eye size={16} />}
            <span>{allVisible ? '全部隐藏' : '全部显示'}</span>
          </button>
        </motion.div>
      )}

      <motion.div
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ delay: 0.1 }}
        className="grid lg:grid-cols-3 gap-4"
      >
        {SECTION_ORDER.map((section) => {
          const theme = SECTION_THEME[section]
          const Icon = getSectionIcon(section)
          const sectionItems = itemsBySection[section]
          const sectionAnsweredCount = sectionItems.filter((item) => answeredItems.has(item.id)).length
          const isCurrentSection = practiceMode === 'proficient'
            ? currentSection === section
            : currentPracticeItem?.section === section
          const isVisible = isPracticeMode ? true : visible[section]
          const canSwitchSection = isPracticeMode && practiceMode === 'proficient' && sectionItems.length > 0

          return (
            <div
              key={section}
              className={`bg-white dark:bg-gray-800 rounded-xl shadow-sm border overflow-hidden transition-colors ${
                isPracticeMode && practiceMode === 'proficient' && isCurrentSection
                  ? 'border-indigo-400 dark:border-indigo-500 ring-1 ring-indigo-200 dark:ring-indigo-900/50'
                  : 'border-gray-100 dark:border-gray-700'
              }`}
            >
              <div className={`flex items-center justify-between px-3 py-2 border-b ${theme.header}`}>
                <button
                  type="button"
                  disabled={!canSwitchSection}
                  onClick={() => {
                    if (!canSwitchSection) return
                    clearDebounceTimer()
                    hideAnswerAndUnlock()
                    setCurrentSection(section)
                    setProficientInput('')
                    setProficientHasError(false)
                  }}
                  className={`flex items-center gap-2 text-left ${canSwitchSection ? 'cursor-pointer' : 'cursor-default'}`}
                >
                  <Icon size={16} className={theme.icon} />
                  <div>
                    <h3 className={`font-semibold text-sm ${theme.accent}`}>
                      {SECTION_LABELS[section]} ({sectionItems.length})
                    </h3>
                    {isPracticeMode && (
                      <p className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
                        已完成 {sectionAnsweredCount}/{sectionItems.length}
                      </p>
                    )}
                  </div>
                </button>
                {!isPracticeMode ? (
                  <button
                    type="button"
                    onClick={() => toggleSection(section)}
                    aria-label={visible[section] ? `隐藏${SECTION_LABELS[section]}` : `显示${SECTION_LABELS[section]}`}
                    aria-pressed={visible[section]}
                    className={`flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium transition-colors ${theme.button}`}
                  >
                    {visible[section] ? <EyeOff size={14} /> : <Eye size={14} />}
                    <span>{visible[section] ? '隐藏' : '显示'}</span>
                  </button>
                ) : practiceMode === 'proficient' && canSwitchSection ? (
                  <span className={`text-xs font-medium ${isCurrentSection ? 'text-indigo-600 dark:text-indigo-300' : 'text-gray-400 dark:text-gray-500'}`}>
                    {isCurrentSection ? '当前分组' : '点击切换'}
                  </span>
                ) : null}
              </div>
              <motion.div
                animate={{
                  maxHeight: isVisible ? 2000 : 0,
                  opacity: isVisible ? 1 : 0,
                }}
                initial={false}
                transition={{ duration: 0.3, ease: 'easeInOut' }}
                style={{ overflow: 'hidden' }}
              >
                {isPracticeMode ? (
                  <PracticeList
                    items={sectionItems}
                    answeredItems={answeredItems}
                    mode={practiceMode}
                    currentPracticeId={currentPracticeId}
                    currentSection={currentSection}
                    section={section}
                    showAnswer={showAnswer}
                    onLongPressStart={practiceMode === 'standard' ? (() => {
                      clearLongPressTimer()
                      longPressTimerRef.current = window.setTimeout(() => {
                        setShowAnswer(true)
                        setInputLocked(true)
                      }, 300)
                    }) : undefined}
                    onLongPressEnd={practiceMode === 'standard' ? hideAnswerAndUnlock : undefined}
                  />
                ) : (
                  <StaticIttoList items={sectionItems} />
                )}
              </motion.div>
            </div>
          )
        })}
      </motion.div>

      {isPracticeMode && (
        <div className="sticky bottom-0 z-10 bg-white/85 dark:bg-gray-800/85 backdrop-blur-md border-t border-gray-200 dark:border-gray-700 px-4 py-3 rounded-t-xl">
          <div className="flex items-center justify-between gap-4 mb-2 flex-wrap">
            <div className="text-xs text-gray-500 dark:text-gray-400 space-y-1">
              <div>
                已完成 {completedCount} / 共 {practiceItems.length} 项
                {practiceMode === 'proficient' && (
                  <span> · 当前分组：{SECTION_LABELS[currentSection]}（{itemsBySection[currentSection].filter((item) => answeredItems.has(item.id)).length}/{itemsBySection[currentSection].length}）</span>
                )}
                {practiceMode === 'standard' && currentPracticeItem && (
                  <span> · 第 {currentPracticeIndex + 1} 项</span>
                )}
              </div>
              {showAnswer && practiceMode === 'proficient' && (
                <div className="text-indigo-600 dark:text-indigo-300">
                  当前显示：{SECTION_LABELS[currentSection]}分组未完成答案（{currentSectionRemainingItems.length} 项）
                </div>
              )}
              {showAnswer && practiceMode === 'standard' && currentPracticeItem && (
                <div className="text-indigo-600 dark:text-indigo-300">
                  当前答案：{currentPracticeItem.name}
                </div>
              )}
            </div>
            <button
              type="button"
              onClick={revealAnswersForThreeSeconds}
              title="查看答案"
              className="shrink-0 p-2 text-gray-500 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
            >
              <svg className="w-5 h-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 className="flex items-center justify-center gap-4">
            {practiceMode === 'proficient' ? (
              <ProficientInputArea
                value={proficientInput}
                isComposing={isComposing}
                inputLocked={inputLocked}
                hasError={proficientHasError}
                onChange={(value) => {
                  setProficientInput(value)
                  setProficientHasError(false)
                }}
                onCompositionStart={() => handleCompositionStart()}
                onCompositionEnd={(value) => handleCompositionEnd(value)}
              />
            ) : currentPracticeItem ? (
              <InputArea
                userInput={userInput}
                charStatuses={charStatuses}
                isComposing={isComposing}
                inputLocked={inputLocked}
                lastErrorTimestamp={lastErrorTimestamp}
                onInputChange={handleInputChange}
                onCompositionStart={(index) => handleCompositionStart(index)}
                onCompositionEnd={(index, value) => handleCompositionEnd(index, value)}
                onPaste={handlePaste}
              />
            ) : null}
          </div>
        </div>
      )}

      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ delay: 0.15 }}
        className="flex items-center justify-between pt-3 border-t border-gray-200 dark:border-gray-700"
      >
        {prevProcess ? (
          <Link
            to={`/process/${prevProcess.id}`}
            state={location.state}
            className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors text-sm"
          >
            <ArrowLeft size={16} />
            <div>
              <div className="text-xs text-gray-400">上一个</div>
              <div className="font-medium">{prevProcess.code} {prevProcess.name}</div>
            </div>
          </Link>
        ) : <div />}
        {nextProcess ? (
          <Link
            to={`/process/${nextProcess.id}`}
            state={location.state}
            className="flex items-center gap-2 text-gray-600 dark:text-gray-400 hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors text-right text-sm"
          >
            <div>
              <div className="text-xs text-gray-400">下一个</div>
              <div className="font-medium">{nextProcess.code} {nextProcess.name}</div>
            </div>
            <ArrowRight size={16} />
          </Link>
        ) : <div />}
      </motion.div>

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

interface StaticIttoListProps {
  items: PracticeItem[]
}

function StaticIttoList({ items }: StaticIttoListProps) {
  return (
    <ul className="divide-y divide-gray-100 dark:divide-gray-700">
      {items.map((item) => {
        const data = item.originalData
        const hasDetail = data?.detail && data.detail.length > 0

        return (
          <li key={item.id} className="px-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-700/50 transition-colors">
            <div className="font-medium text-gray-900 dark:text-white text-sm">{data?.name || data?.id}</div>
            {data?.nameEn && <div className="text-xs text-gray-500 dark:text-gray-400">{data.nameEn}</div>}
            {hasDetail && (
              <div className="mt-1.5 text-xs text-gray-600 dark:text-gray-400">
                {data.detail.map((detailItem: any, idx: number) => (
                  <span key={detailItem.id || idx}>
                    {detailItem.label}
                    {idx < data.detail.length - 1 && '、'}
                  </span>
                ))}
              </div>
            )}
            {data?.note && (
              <div className="mt-1.5 text-xs text-gray-500 dark:text-gray-400 italic">
                💡 {data.note}
              </div>
            )}
          </li>
        )
      })}
    </ul>
  )
}

interface PracticeListProps {
  items: PracticeItem[]
  answeredItems: Set<string>
  mode: 'standard' | 'proficient'
  currentPracticeId: string | null
  currentSection: IttoSection
  section: IttoSection
  showAnswer: boolean
  onLongPressStart?: () => void
  onLongPressEnd?: () => void
}

function PracticeList({
  items,
  answeredItems,
  mode,
  currentPracticeId,
  currentSection,
  section,
  showAnswer,
  onLongPressStart,
  onLongPressEnd,
}: PracticeListProps) {
  if (items.length === 0) return null

  return (
    <ul className="divide-y divide-gray-100 dark:divide-gray-700">
      {items.map((item) => {
        const isAnswered = answeredItems.has(item.id)
        const isCurrent = mode === 'standard' && item.id === currentPracticeId
        const isCurrentSection = mode === 'proficient' && currentSection === section
        const shouldRevealAnswer = mode === 'standard'
          ? isCurrent && showAnswer
          : isCurrentSection && showAnswer
        const data = item.originalData
        const hasDetail = data?.detail && data.detail.length > 0

        return (
          <li key={item.id} className="px-3 py-2">
            <div
              className={`rounded-md px-2.5 py-1.5 text-sm transition-colors ${
                isCurrent
                  ? 'border-2 border-indigo-400 dark:border-indigo-500 bg-indigo-50/60 dark:bg-indigo-900/20'
                  : isAnswered
                    ? 'border border-transparent'
                    : isCurrentSection
                      ? 'border border-indigo-200 dark:border-indigo-800/60 bg-indigo-50/30 dark:bg-indigo-900/10'
                      : 'border border-dashed border-gray-300 dark:border-gray-600'
              }`}
              onPointerDown={isCurrent ? (event) => { event.preventDefault(); onLongPressStart?.() } : undefined}
              onPointerUp={isCurrent ? onLongPressEnd : undefined}
              onPointerLeave={isCurrent ? onLongPressEnd : undefined}
              onPointerCancel={isCurrent ? onLongPressEnd : undefined}
            >
              {isAnswered ? (
                <div>
                  <div className="flex items-center justify-between gap-2">
                    <span className="font-medium text-gray-900 dark:text-white">{item.name}</span>
                    <Check size={14} className="text-green-500 shrink-0" />
                  </div>
                  {data?.nameEn && (
                    <div className="text-xs text-gray-500 dark:text-gray-400 mt-0.5">
                      {data.nameEn}
                    </div>
                  )}
                  {hasDetail && (
                    <div className="mt-1.5 text-xs text-gray-600 dark:text-gray-400">
                      {data.detail.map((detailItem: any, idx: number) => (
                        <span key={detailItem.id || idx}>
                          {detailItem.label}
                          {idx < data.detail.length - 1 && '、'}
                        </span>
                      ))}
                    </div>
                  )}
                  {data?.note && (
                    <div className="mt-1.5 text-xs text-gray-500 dark:text-gray-400 italic">
                      💡 {data.note}
                    </div>
                  )}
                </div>
              ) : shouldRevealAnswer ? (
                <div className="flex items-center justify-between gap-2">
                  <span className="font-medium text-indigo-700 dark:text-indigo-300">{item.name}</span>
                  <span className="text-xs text-indigo-400">答案</span>
                </div>
              ) : (
                <div className="flex items-center justify-between gap-2">
                  <span className={`font-medium select-none ${
                    isCurrentSection || isCurrent
                      ? 'text-indigo-400 dark:text-indigo-500'
                      : 'text-gray-300 dark:text-gray-600'
                  }`}>
                    {'_'.repeat(item.name.length)}
                  </span>
                  {mode === 'proficient' && isCurrentSection && (
                    <span className="text-[11px] text-indigo-300 dark:text-indigo-500">待输入</span>
                  )}
                </div>
              )}
            </div>
          </li>
        )
      })}
    </ul>
  )
}
