import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Zap, ArrowLeft, Bot, Clock, Sun, Moon, PanelRightOpen, X, Brain } from 'lucide-react'
import { ChatContainer } from './components/Chat/ChatContainer'
import { TopicList } from './components/Sidebar/TopicList'
import { SchedulerJobList } from './components/Sidebar/SchedulerJobList'
import { MemoryPanel } from './components/Panel/MemoryPanel'
import { SkillList } from './components/Panel/SkillList'
import { TodoPanel } from './components/Panel/TodoPanel'
import { ConnectionStatus } from './components/ConnectionStatus'
import { ChannelSelector } from './components/Header/ChannelSelector'
import { SessionSelector } from './components/Header/SessionSelector'
import { useWebSocket } from './hooks/useWebSocket'
import { useChat } from './hooks/useChat'
import type { ChatMessage, Command, Attachment, SchedulerJobSessionLookup } from './types/protocol'

const WS_URL = 'ws://127.0.0.1:19876/ws'

function App() {
  const lastAutoSwitchedTopicRef = useRef<string | null>(null)

  const {
    // 连接状态
    isConnected,
    // Session 状态
    session,
    sessionId,
    chatId,
    // Topic 状态
    topics,
    selectedTopic,
    // 消息状态
    messages,
    isLoading,
    isReadOnly,
    // 子智能体视图
    subAgentView,
    // 记忆
    memories,
    requestMemoryList,
    createMemory,
    updateMemory,
    deleteMemory,
    // 技能
    skills,
    requestSkillList,
    todos,
    requestTodoList,
    // 定时任务
    schedulerJobs,
    sidebarTab,
    setSidebarTab,
    requestSchedulerJobList,
    schedulerView,
    enterSchedulerJobView,
    exitSchedulerJobView,
    // 通道
    channels,
    selectedChannel,
    selectChannel,
    requestChannelList,
    // Session
    sessions,
    selectedSessionId,
    selectSession,
    // 方法
    handleMessage,
    handleCommand,
    clearMessages,
    handleServerMessage,
    selectTopic,
    createTopic,
    switchTopic,
    deleteTopic,
    requestSessionList,
    requestTopicList,
    topicRefreshTrigger,
    enterSubAgentView,
    exitSubAgentView,
    handleStop,
  } = useChat()

  const { status, sendMessage } = useWebSocket({
    url: WS_URL,
    onMessage: handleServerMessage,
  })

  // ---- 主题状态 ----

  const [memoryPanelOpen, setMemoryPanelOpen] = useState(() => {
    try {
      return localStorage.getItem('picobot-memory-panel-open') !== 'false'
    } catch {
      return false
    }
  })

  const toggleMemoryPanel = useCallback((open: boolean) => {
    setMemoryPanelOpen(open)
    localStorage.setItem('picobot-memory-panel-open', String(open))
  }, [])

  const [rightPanelTab, setRightPanelTab] = useState<'memory' | 'skill'>('memory')

  const [theme, setTheme] = useState<'dark' | 'light'>(() => {
    const saved = localStorage.getItem('picobot-theme')
    return saved === 'light' ? 'light' : 'dark'
  })

  useEffect(() => {
    const root = document.documentElement
    if (theme === 'light') {
      root.classList.add('light')
    } else {
      root.classList.remove('light')
    }
    localStorage.setItem('picobot-theme', theme)

    // 切换时启用平滑过渡
    root.classList.add('theme-transitioning')
    const timer = setTimeout(() => {
      root.classList.remove('theme-transitioning')
    }, 350)
    return () => clearTimeout(timer)
  }, [theme])

  const [showThinking, setShowThinking] = useState(() => {
    return localStorage.getItem('picobot-show-thinking') !== 'false'
  })

  useEffect(() => {
    localStorage.setItem('picobot-show-thinking', String(showThinking))
  }, [showThinking])

  // ---- WebSocket 初始化 ----

  // Step 1: 连接建立后先请求通道列表
  useEffect(() => {
    if (isConnected && status === 'connected') {
      const cmd = requestChannelList()
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    }
  }, [isConnected, status, handleCommand, sendMessage, requestChannelList])

  // Step 2: 通道列表加载后，请求选中通道的 Session 列表
  useEffect(() => {
    if (channels.length > 0 && status === 'connected') {
      const sessionCmd = requestSessionList()
      handleCommand(sessionCmd)
      sendMessage({ type: 'command', payload: JSON.stringify(sessionCmd) })
    }
  }, [channels.length, status, handleCommand, sendMessage, requestSessionList])

  // Session 加载后自动加载 Topics
  useEffect(() => {
    if (sessionId && status === 'connected') {
      const topicCmd = requestTopicList()
      if (topicCmd) {
        handleCommand(topicCmd)
        sendMessage({ type: 'command', payload: JSON.stringify(topicCmd) })
      }
    }
  }, [sessionId, status, handleCommand, sendMessage, requestTopicList])

  // 话题描述异步生成后自动刷新话题列表
  useEffect(() => {
    if (topicRefreshTrigger === 0) return
    if (status !== 'connected') return
    const topicCmd = requestTopicList()
    if (!topicCmd) return

    const timer = setTimeout(() => {
      handleCommand(topicCmd)
      sendMessage({ type: 'command', payload: JSON.stringify(topicCmd) })
    }, 500)

    return () => clearTimeout(timer)
  }, [topicRefreshTrigger])

  // Topics 加载后，自动选择第一个（仅当用户尚未手动选择 topic 时）
  useEffect(() => {
    if (topics.length === 0 || status !== 'connected') {
      return
    }
    // 用户已经选中了某个 topic → 不要抢走
    if (selectedTopic) {
      return
    }

    const firstTopic = topics[0]
    if (lastAutoSwitchedTopicRef.current === firstTopic.id) {
      return
    }

    lastAutoSwitchedTopicRef.current = firstTopic.id
    selectTopic(firstTopic.id)
    const cmd = switchTopic(firstTopic.id)
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [topics, status, selectedTopic, selectTopic, switchTopic, handleCommand, sendMessage]);

  const handleSendMessage = useCallback(
    (content: string, attachments: Attachment[] = []) => {
      if (isReadOnly || !sessionId) {
        return
      }

      if (content.startsWith('/')) {
        const parts = content.slice(1).split(' ')
        const command = parts[0]
        const args = parts.slice(1)

        let cmd: Command
        switch (command) {
          case 'new':
            cmd = createTopic(args.join(' ') || undefined)
            break
          case 'list':
            cmd = { type: 'list_sessions', include_archived: args[0] === 'all' }
            break
          case 'use':
            if (args[0]) {
              cmd = { type: 'switch_topic', topic_id: args[0] }
            } else {
              alert('Usage: /use <topic_id>')
              return
            }
            break
          case 'save':
            cmd = { type: 'save_topic', filepath: args[0] || undefined, include_subagents: false }
            break
          case 'stop':
            cmd = { type: 'stop_execution' }
            break
          default:
            alert(`Unknown command: /${command}`)
            return
        }

        handleCommand(cmd)
        sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
      } else {
        handleMessage(content, attachments)
        sendMessage({
          type: 'message',
          content,
          attachments,
          chat_id: chatId,
        })
      }
    },
    [sendMessage, handleMessage, handleCommand, sessionId, chatId, isReadOnly]
  )

  const handleStopExecution = useCallback(() => {
    const cmd = handleStop()
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [sendMessage, handleCommand, handleStop])

  const handleCreateTopic = useCallback(() => {
    if (isReadOnly || !sessionId) {
      return
    }

    const cmd = createTopic()
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [sendMessage, handleCommand, createTopic, sessionId, isReadOnly])

  const handleRefreshTopics = useCallback(() => {
    if (!sessionId) return
    const cmd = requestTopicList()
    if (cmd) {
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    }
  }, [sessionId, requestTopicList, handleCommand, sendMessage])

  const handleSwitchTopic = useCallback(
    (topicId: string) => {
      selectTopic(topicId)
      const cmd = switchTopic(topicId)
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    },
    [sendMessage, handleCommand, switchTopic, selectTopic]
  )

  const handleDeleteTopic = useCallback(
    (topicId: string) => {
      const cmd = deleteTopic(topicId)
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
      // 如果删除的是当前选中话题，清空选中状态和消息
      if (topicId === selectedTopic) {
        selectTopic('')
        clearMessages()
      }
    },
    [sendMessage, handleCommand, deleteTopic, selectedTopic, selectTopic, clearMessages]
  )

  const handleNavigateToSubAgent = useCallback(
    (taskId: string, description: string) => {
      const cmd = enterSubAgentView(taskId, description)
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    },
    [enterSubAgentView, handleCommand, sendMessage]
  )

  const handleExitSubAgentView = useCallback(() => {
    exitSubAgentView()
  }, [exitSubAgentView])

  // 切换到定时任务 tab 时自动获取列表
  useEffect(() => {
    if (sidebarTab === 'scheduler' && status === 'connected') {
      const cmd = requestSchedulerJobList()
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    }
  }, [sidebarTab, status, handleCommand, sendMessage, requestSchedulerJobList])

  // 连接就绪时自动拉取记忆、技能和待办列表
  useEffect(() => {
    if (status === 'connected') {
      const memCmd = requestMemoryList()
      handleCommand(memCmd)
      sendMessage({ type: 'command', payload: JSON.stringify(memCmd) })
      const skillCmd = requestSkillList()
      handleCommand(skillCmd)
      sendMessage({ type: 'command', payload: JSON.stringify(skillCmd) })
      const todoCmd = requestTodoList()
      handleCommand(todoCmd)
      sendMessage({ type: 'command', payload: JSON.stringify(todoCmd) })
    }
  }, [status, handleCommand, sendMessage, requestMemoryList, requestSkillList, requestTodoList])

  const handleRefreshMemories = useCallback(() => {
    const cmd = requestMemoryList()
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [handleCommand, sendMessage, requestMemoryList])

  const handleRefreshSkills = useCallback(() => {
    const cmd = requestSkillList()
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [handleCommand, sendMessage, requestSkillList])

  const sendMemoryCommand = useCallback((cmd: Command) => {
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [handleCommand, sendMessage])

  const handleRefreshSchedulerJobs = useCallback(() => {
    const cmd = requestSchedulerJobList()
    handleCommand(cmd)
    sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
  }, [handleCommand, sendMessage, requestSchedulerJobList])

  const handleViewSchedulerJob = useCallback(
    (lookup: SchedulerJobSessionLookup, jobId: string, description: string) => {
      const cmd = enterSchedulerJobView(lookup, jobId, description)
      handleCommand(cmd)
      sendMessage({ type: 'command', payload: JSON.stringify(cmd) })
    },
    [enterSchedulerJobView, handleCommand, sendMessage]
  )

  const handleExitSchedulerJobView = useCallback(() => {
    exitSchedulerJobView()
  }, [exitSchedulerJobView])

  const handleSwitchChannel = useCallback(
    (channelId: string) => {
      if (channelId === selectedChannel) return
      lastAutoSwitchedTopicRef.current = null
      selectChannel(channelId)
    },
    [selectedChannel, selectChannel]
  )

  const handleSelectSession = useCallback(
    (sessionId: string) => {
      if (sessionId === selectedSessionId) return
      lastAutoSwitchedTopicRef.current = null
      selectSession(sessionId)
    },
    [selectedSessionId, selectSession]
  )

  const chatMessages = useMemo(() => {
    const result: ChatMessage[] = []
    const toolCallIndex = new Map<string, number>()

    for (const msg of messages) {
      if (msg.type === 'tool_call') {
        toolCallIndex.set(msg.toolCallId || msg.id, result.length)
        result.push({
          ...msg,
          type: 'merged_tool',
          status: 'calling',
          callContent: msg.content,
          resultContent: '',
        })
      } else if (msg.type === 'tool_result') {
        const idx = toolCallIndex.get(msg.toolCallId || msg.id)
        if (idx !== undefined) {
          result[idx] = {
            ...result[idx],
            status: 'result',
            resultContent: msg.content,
            durationMs: msg.durationMs,
          }
        }
      } else if (msg.type === 'tool_pending') {
        const idx = toolCallIndex.get(msg.toolCallId || msg.id)
        if (idx !== undefined) {
          result[idx] = {
            ...result[idx],
            status: 'pending',
            resultContent: msg.content,
          }
        }
      } else {
        result.push(msg)
      }
    }

    return result
  }, [messages])

  return (
    <div className="flex h-screen flex-col bg-[var(--bg-primary)] text-[var(--text-primary)] overflow-hidden">
      {/* Header */}
      <header className="flex items-center justify-between border-b border-[var(--border-color)] bg-[var(--bg-secondary)]/80 backdrop-blur-md px-6 py-4">
        <div className="flex items-center gap-4">
          <div className="flex items-center gap-2">
            <Zap className="h-6 w-6 text-[var(--accent-cyan)]" />
            <h1 className="text-xl font-bold tracking-tight">
              <span className="text-[var(--text-primary)]">Pico</span>
              <span className="text-[var(--accent-cyan)] glow-text">Bot</span>
            </h1>
          </div>
          <div className="h-4 w-px bg-[var(--divider-color)]" />
          <ConnectionStatus status={status} />
          {/* 主题切换按钮 */}
          <div className="h-4 w-px bg-[var(--divider-color)]" />
          <button
            onClick={() => setTheme(prev => prev === 'dark' ? 'light' : 'dark')}
            className="flex h-8 w-8 items-center justify-center rounded-lg text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:bg-[var(--overlay-hover)] transition-all"
            title={theme === 'dark' ? '切换到亮色主题' : '切换到暗色主题'}
            aria-label={theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'}
          >
            {theme === 'dark' ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
          </button>
          <button
            onClick={() => setShowThinking(prev => !prev)}
            className={`flex h-8 w-8 items-center justify-center rounded-lg transition-all ${
              showThinking
                ? 'text-purple-400 hover:text-purple-300 bg-purple-500/10 hover:bg-purple-500/20'
                : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)] hover:bg-[var(--overlay-hover)]'
            }`}
            title={showThinking ? '隐藏思考过程' : '显示思考过程'}
            aria-label="Toggle thinking display"
          >
            <Brain className="h-4 w-4" />
          </button>
        </div>
        <div className="flex items-center gap-4 text-sm text-[var(--text-secondary)]">
          <ChannelSelector
            channels={channels}
            selectedChannel={selectedChannel}
            onSelectChannel={handleSwitchChannel}
          />
          <SessionSelector
            sessions={sessions}
            selectedSessionId={selectedSessionId}
            onSelectSession={handleSelectSession}
          />
        </div>
      </header>

      {/* Main Content */}
      <div className="flex flex-1 overflow-hidden relative">
        {/* Left Sidebar */}
        <div className={`w-72 shrink-0 border-r border-[var(--border-color)] bg-[var(--bg-secondary)]/50 flex flex-col ${subAgentView || schedulerView ? 'opacity-50 pointer-events-none' : ''}`}>
          {/* Tab 栏 */}
          <div className="flex border-b border-[var(--border-color)]">
            <button
              onClick={() => setSidebarTab('topics')}
              className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${
                sidebarTab === 'topics'
                  ? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
                  : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
              }`}
            >
              话题
            </button>
            <button
              onClick={() => setSidebarTab('scheduler')}
              className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${
                sidebarTab === 'scheduler'
                  ? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
                  : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
              }`}
            >
              定时任务
            </button>
          </div>

          <div className="flex-1 overflow-hidden">
            {sidebarTab === 'topics' ? (
              <TopicList
                sessionId={sessionId}
                topics={topics}
                currentTopicId={selectedTopic}
                isReadOnly={isReadOnly}
                onCreateTopic={handleCreateTopic}
                onRefresh={handleRefreshTopics}
                onSwitchTopic={handleSwitchTopic}
                onDeleteTopic={handleDeleteTopic}
              />
            ) : (
              <SchedulerJobList
                jobs={schedulerJobs}
                onRefresh={handleRefreshSchedulerJobs}
                onViewJob={handleViewSchedulerJob}
                sessionId={sessionId}
              />
            )}
          </div>
        </div>

        {/* Center - Chat */}
        <div className="flex-1 min-w-0 bg-[var(--bg-primary)] flex flex-col">
          {/* Scheduler job view back bar */}
          {schedulerView && (
            <div className="shrink-0 border-b border-[var(--border-color)] bg-[var(--bg-secondary)]/80 px-4 py-2 flex items-center gap-4">
              <button
                onClick={handleExitSchedulerJobView}
                className="flex items-center gap-1.5 text-sm text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 transition-colors"
              >
                <ArrowLeft className="h-4 w-4" />
                <span>返回定时任务列表</span>
              </button>
              <div className="h-4 w-px bg-[var(--divider-color)]" />
              <div className="flex items-center gap-1.5 text-sm text-[var(--text-secondary)]">
                <Clock className="h-4 w-4 text-amber-400" />
                <span className="text-[var(--text-muted)]">定时任务:</span>
                <span className="text-[var(--text-primary)] font-medium font-mono text-xs truncate max-w-[250px]">{schedulerView.description}</span>
              </div>
              <div className="h-4 w-px bg-[var(--divider-color)]" />
              <div className="flex items-center gap-1.5 text-sm">
                <span className="text-[var(--text-muted)]">通道:</span>
                <span className="text-[var(--text-secondary)]">{schedulerView.channel}</span>
              </div>
            </div>
          )}
          {/* Sub-agent back bar */}
          {subAgentView && (
            <div className="shrink-0 border-b border-[var(--border-color)] bg-[var(--bg-secondary)]/80 px-4 py-2 flex items-center gap-4">
              <button
                onClick={handleExitSubAgentView}
                className="flex items-center gap-1.5 text-sm text-[var(--accent-cyan)] hover:text-[var(--accent-cyan)]/80 transition-colors"
              >
                <ArrowLeft className="h-4 w-4" />
                <span>返回主会话</span>
              </button>
              <div className="h-4 w-px bg-[var(--divider-color)]" />
              <div className="flex items-center gap-1.5 text-sm text-[var(--text-secondary)]">
                <Bot className="h-4 w-4 text-violet-400" />
                <span className="text-[var(--text-muted)]">子智能体:</span>
                <span className="text-[var(--text-primary)] font-medium">{subAgentView.description}</span>
              </div>
              <div className="h-4 w-px bg-[var(--divider-color)]" />
              <div className="flex items-center gap-1.5 text-sm">
                <span className="text-[var(--text-muted)]">类型:</span>
                <span className="text-[var(--text-secondary)]">{subAgentView.subagentType || '...'}</span>
              </div>
              <div className="h-4 w-px bg-[var(--divider-color)]" />
              <div className="flex items-center gap-1.5 text-sm">
                <span className="text-[var(--text-muted)]">状态:</span>
                <span className={`font-medium ${
                  subAgentView.status === 'completed' ? 'text-emerald-400' :
                  subAgentView.status === 'failed' ? 'text-red-400' :
                  subAgentView.status === 'timeout' ? 'text-amber-400' :
                  subAgentView.status === 'running' ? 'text-amber-400' :
                  'text-[var(--text-secondary)]'
                }`}>
                  {subAgentView.status === 'completed' ? '已完成' :
                   subAgentView.status === 'failed' ? '失败' :
                   subAgentView.status === 'timeout' ? '超时' :
                   subAgentView.status === 'running' ? '执行中' :
                   subAgentView.status === 'loading' ? '加载中...' :
                   subAgentView.status}
                </span>
              </div>
            </div>
          )}
          <div className="flex-1 min-h-0">
            <ChatContainer
              key={selectedTopic ?? 'no-topic'}
              messages={chatMessages}
              isLoading={isLoading}
              isReadOnly={subAgentView || schedulerView ? true : isReadOnly}
              channelName={
                schedulerView ? `定时任务: ${schedulerView.description}` :
                subAgentView ? `子智能体: ${subAgentView.description}` :
                (session?.title ?? channels.find(c => c.id === selectedChannel)?.name ?? 'PicoBot')
              }
              onSendMessage={subAgentView || schedulerView ? () => {} : handleSendMessage}
              onNavigateToSubAgent={handleNavigateToSubAgent}
              onStop={handleStopExecution}
              showThinking={showThinking}
            />
          </div>
        </div>

        {/* Right Sidebar - Memory & Skill Panel (collapsible, tabbed) */}
        <div className={`shrink-0 border-l border-[var(--border-color)] bg-[var(--bg-secondary)]/50 transition-all duration-300 ease-out overflow-hidden ${memoryPanelOpen ? 'w-80' : 'w-0 border-l-0'}`}>
          <div className={`w-80 h-full flex flex-col ${memoryPanelOpen ? '' : 'invisible'}`}>
            {/* Tab 栏 */}
            <div className="shrink-0 flex border-b border-[var(--border-color)]">
              <button
                onClick={() => setRightPanelTab('memory')}
                className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${
                  rightPanelTab === 'memory'
                    ? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
                    : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
                }`}
              >
                记忆
              </button>
              <button
                onClick={() => setRightPanelTab('skill')}
                className={`flex-1 py-2.5 text-sm font-medium text-center transition-colors ${
                  rightPanelTab === 'skill'
                    ? 'text-[var(--accent-cyan)] border-b-2 border-[var(--accent-cyan)]'
                    : 'text-[var(--text-muted)] hover:text-[var(--text-secondary)]'
                }`}
              >
                技能
              </button>
              <button onClick={() => toggleMemoryPanel(false)} className="px-2 py-2.5 text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors" title="收起">
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
            {/* Panel content */}
            <div className="flex-1 min-h-0">
              {rightPanelTab === 'memory' ? (
                <MemoryPanel
                  memories={memories}
                  onRefresh={handleRefreshMemories}
                  onCreateMemory={createMemory}
                  onUpdateMemory={updateMemory}
                  onDeleteMemory={deleteMemory}
                  sendCommand={sendMemoryCommand}
                />
              ) : (
                <SkillList
                  skills={skills}
                  onRefresh={handleRefreshSkills}
                />
              )}
            </div>
          </div>
        </div>

        {/* Reopen button — visible when panel is collapsed */}
        {!memoryPanelOpen && (
          <div className="absolute right-0 top-1/2 -translate-y-1/2 z-10">
            <button
              onClick={() => toggleMemoryPanel(true)}
              className="flex items-center gap-1.5 px-2 py-4 rounded-l-xl bg-[var(--bg-secondary)]/80 backdrop-blur-sm border border-r-0 border-[var(--border-color)] text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:border-[var(--accent-cyan)]/30 transition-all duration-300 shadow-lg"
              title="展开记忆面板"
            >
              <PanelRightOpen className="h-4 w-4" />
            </button>
          </div>
        )}
      </div>

      {/* 悬浮 Todo 面板 */}
      <TodoPanel
        todos={todos}
        requestTodoList={requestTodoList}
        sendCommand={sendMemoryCommand}
      />
    </div>
  )
}

export default App
