﻿import { ReactNode, useEffect, useMemo, useState } from 'react';
import { motion } from 'framer-motion';
import { getStoredGatewayUrl } from '../lib/gateway-client';
import { useGatewayStore, type PluginStatus } from '../store/gatewayStore';
import { toChatAgent, useChatStore, type CodeBlock } from '../store/chatStore';
import {
  Wifi, WifiOff, Bot, BarChart3, Plug, RefreshCw,
  MessageSquare, Cpu, FileText, User, Activity, Brain,
  Shield, Sparkles, GraduationCap, List, Network
} from 'lucide-react';

// === Helper to extract code blocks from markdown content ===
function extractCodeBlocksFromContent(content: string): CodeBlock[] {
  const blocks: CodeBlock[] = [];
  const regex = /```(\w*)\n([\s\S]*?)```/g;
  let match;

  while ((match = regex.exec(content)) !== null) {
    const language = match[1] || 'text';
    const codeContent = match[2].trim();

    // Try to extract filename from first line comment
    let filename: string | undefined;
    let actualContent = codeContent;

    // Check for filename patterns like "# filename.py" or "// filename.js"
    const firstLine = codeContent.split('\n')[0];
    const filenameMatch = firstLine.match(/^(?:#|\/\/|\/\*|<!--)\s*([^\s]+\.\w+)/);
    if (filenameMatch) {
      filename = filenameMatch[1];
      actualContent = codeContent.split('\n').slice(1).join('\n').trim();
    }

    blocks.push({
      language,
      filename,
      content: actualContent,
    });
  }

  return blocks;
}

// === Tab Button Component ===
function TabButton({
  active,
  onClick,
  icon,
  label,
}: {
  active: boolean;
  onClick: () => void;
  icon: ReactNode;
  label: string;
}) {
  return (
    <button
      onClick={onClick}
      className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${
        active
          ? 'bg-emerald-100 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300'
          : 'text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-700 dark:hover:text-gray-300'
      }`}
    >
      {icon}
      <span>{label}</span>
    </button>
  );
}
import { MemoryPanel } from './MemoryPanel';
import { MemoryGraph } from './MemoryGraph';
import { ReflectionLog } from './ReflectionLog';
import { AutonomyConfig } from './AutonomyConfig';
import { ActiveLearningPanel } from './ActiveLearningPanel';
import { CodeSnippetPanel, type CodeSnippet } from './CodeSnippetPanel';
import { cardHover, defaultTransition } from '../lib/animations';
import { Button, Badge } from './ui';
import { getPersonalityById } from '../lib/personality-presets';
import { silentErrorHandler } from '../lib/error-utils';

export function RightPanel() {
  const {
    connectionState, gatewayVersion, error, clones, usageStats, pluginStatus,
    connect, loadClones, loadUsageStats, loadPluginStatus, workspaceInfo, quickConfig, updateClone,
  } = useGatewayStore();
  const { messages, currentModel, currentAgent, setCurrentAgent } = useChatStore();
  const [activeTab, setActiveTab] = useState<'status' | 'files' | 'agent' | 'memory' | 'reflection' | 'autonomy' | 'learning'>('status');
  const [memoryViewMode, setMemoryViewMode] = useState<'list' | 'graph'>('list');
  const [isEditingAgent, setIsEditingAgent] = useState(false);
  const [agentDraft, setAgentDraft] = useState<AgentDraft | null>(null);

  const connected = connectionState === 'connected';
  const selectedClone = useMemo(
    () => clones.find((clone) => clone.id === currentAgent?.id),
    [clones, currentAgent?.id]
  );
  const focusAreas = selectedClone?.scenarios?.length ? selectedClone.scenarios : ['coding', 'research'];
  const bootstrapFiles = selectedClone?.bootstrapFiles || [];
  const gatewayUrl = quickConfig.gatewayUrl || getStoredGatewayUrl();

  useEffect(() => {
    if (!selectedClone || isEditingAgent) return;
    setAgentDraft(createAgentDraft(selectedClone, currentModel));
  }, [selectedClone, currentModel, isEditingAgent]);

  // Load data when connected
  useEffect(() => {
    if (connected) {
      loadClones();
      loadUsageStats();
      loadPluginStatus();
    }
  }, [connected]);

  const handleReconnect = () => {
    connect().catch(silentErrorHandler('RightPanel'));
  };

  const handleStartEdit = () => {
    if (!selectedClone) return;
    setAgentDraft(createAgentDraft(selectedClone, currentModel));
    setIsEditingAgent(true);
  };

  const handleCancelEdit = () => {
    if (selectedClone) {
      setAgentDraft(createAgentDraft(selectedClone, currentModel));
    }
    setIsEditingAgent(false);
  };

  const handleSaveAgent = async () => {
    if (!selectedClone || !agentDraft || !agentDraft.name.trim()) return;
    const updatedClone = await updateClone(selectedClone.id, {
      name: agentDraft.name.trim(),
      role: agentDraft.role.trim() || undefined,
      nickname: agentDraft.nickname.trim() || undefined,
      model: agentDraft.model.trim() || undefined,
      scenarios: agentDraft.scenarios.split(',').map((item) => item.trim()).filter(Boolean),
      workspaceDir: agentDraft.workspaceDir.trim() || undefined,
      userName: agentDraft.userName.trim() || undefined,
      userRole: agentDraft.userRole.trim() || undefined,
      restrictFiles: agentDraft.restrictFiles,
      privacyOptIn: agentDraft.privacyOptIn,
    });
    if (updatedClone) {
      setCurrentAgent(toChatAgent(updatedClone));
      setAgentDraft(createAgentDraft(updatedClone, updatedClone.model || currentModel));
      setIsEditingAgent(false);
    }
  };

  const userMsgCount = messages.filter(m => m.role === 'user').length;
  const assistantMsgCount = messages.filter(m => m.role === 'assistant').length;
  const toolCallCount = messages.filter(m => m.role === 'tool').length;
  const runtimeSummary = connected ? '已连接' : connectionState === 'connecting' ? '连接中...' : connectionState === 'reconnecting' ? '重连中...' : '未连接';
  const userNameDisplay = selectedClone?.userName || quickConfig.userName || '未设置';
  const userAddressing = selectedClone?.nickname || selectedClone?.userName || quickConfig.userName || '未设置';
  const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone || '系统时区';

  // Extract code blocks from all messages (both from codeBlocks property and content parsing)
  const codeSnippets = useMemo((): CodeSnippet[] => {
    const snippets: CodeSnippet[] = [];
    let globalIndex = 0;

    for (let msgIdx = 0; msgIdx < messages.length; msgIdx++) {
      const msg = messages[msgIdx];

      // First, add any existing codeBlocks from the message
      if (msg.codeBlocks && msg.codeBlocks.length > 0) {
        for (const block of msg.codeBlocks) {
          snippets.push({
            id: `${msg.id}-codeblock-${globalIndex}`,
            block,
            messageIndex: msgIdx,
          });
          globalIndex++;
        }
      }

      // Then, extract code blocks from the message content
      if (msg.content) {
        const extractedBlocks = extractCodeBlocksFromContent(msg.content);
        for (const block of extractedBlocks) {
          snippets.push({
            id: `${msg.id}-extracted-${globalIndex}`,
            block,
            messageIndex: msgIdx,
          });
          globalIndex++;
        }
      }
    }

    return snippets;
  }, [messages]);

  return (
    <aside className="w-full bg-white dark:bg-gray-900 flex flex-col">
      {/* 顶部工具栏 - Tab 栏 */}
      <div className="border-b border-gray-200 dark:border-gray-700 flex-shrink-0">
        {/* 主 Tab 行 */}
        <div className="flex items-center px-2 pt-2 gap-1">
          <TabButton
            active={activeTab === 'status'}
            onClick={() => setActiveTab('status')}
            icon={<Activity className="w-4 h-4" />}
            label="状态"
          />
          <TabButton
            active={activeTab === 'agent'}
            onClick={() => setActiveTab('agent')}
            icon={<User className="w-4 h-4" />}
            label="Agent"
          />
          <TabButton
            active={activeTab === 'files'}
            onClick={() => setActiveTab('files')}
            icon={<FileText className="w-4 h-4" />}
            label="文件"
          />
          <TabButton
            active={activeTab === 'memory'}
            onClick={() => setActiveTab('memory')}
            icon={<Brain className="w-4 h-4" />}
            label="记忆"
          />
        </div>
        {/* 第二行 Tab */}
        <div className="flex items-center px-2 pb-2 gap-1">
          <TabButton
            active={activeTab === 'reflection'}
            onClick={() => setActiveTab('reflection')}
            icon={<Sparkles className="w-4 h-4" />}
            label="反思"
          />
          <TabButton
            active={activeTab === 'autonomy'}
            onClick={() => setActiveTab('autonomy')}
            icon={<Shield className="w-4 h-4" />}
            label="自主"
          />
          <TabButton
            active={activeTab === 'learning'}
            onClick={() => setActiveTab('learning')}
            icon={<GraduationCap className="w-4 h-4" />}
            label="学习"
          />
        </div>
      </div>

      {/* 消息统计 */}
      <div className="px-4 py-2 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between text-xs">
        <div className="flex items-center gap-2 text-gray-500 dark:text-gray-400">
          <BarChart3 className="w-3.5 h-3.5" />
          <span>{messages.length} 条消息</span>
          <span className="text-gray-300 dark:text-gray-600">|</span>
          <span>{userMsgCount} 用户 / {assistantMsgCount} 助手</span>
        </div>
        <div className={`flex items-center gap-1 ${connected ? 'text-emerald-500' : 'text-gray-400'}`}>
          {connected ? <Wifi className="w-3.5 h-3.5" /> : <WifiOff className="w-3.5 h-3.5" />}
          <span>{runtimeSummary}</span>
        </div>
      </div>

      <div className="flex-1 overflow-y-auto custom-scrollbar p-4 space-y-4">
        {activeTab === 'memory' ? (
          <div className="space-y-3">
            {/* 视图切换 */}
            <div className="flex items-center gap-1 p-1 bg-gray-100 dark:bg-gray-800 rounded-lg">
              <button
                onClick={() => setMemoryViewMode('list')}
                className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${
                  memoryViewMode === 'list'
                    ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 shadow-sm'
                    : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'
                }`}
              >
                <List className="w-3.5 h-3.5" />
                列表
              </button>
              <button
                onClick={() => setMemoryViewMode('graph')}
                className={`flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-medium transition-colors ${
                  memoryViewMode === 'graph'
                    ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 shadow-sm'
                    : 'text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300'
                }`}
              >
                <Network className="w-3.5 h-3.5" />
                图谱
              </button>
            </div>

            {/* 内容区域 */}
            {memoryViewMode === 'list' ? (
              <MemoryPanel />
            ) : (
              <div className="h-[400px] rounded-lg overflow-hidden border border-gray-200 dark:border-gray-700">
                <MemoryGraph />
              </div>
            )}
          </div>
        ) : activeTab === 'reflection' ? (
          <ReflectionLog />
        ) : activeTab === 'autonomy' ? (
          <AutonomyConfig />
        ) : activeTab === 'learning' ? (
          <ActiveLearningPanel />
        ) : activeTab === 'agent' ? (
          <div className="space-y-4">
            <motion.div
              whileHover={cardHover}
              transition={defaultTransition}
              className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
            >
              <div className="flex items-start justify-between gap-3">
                <div className="flex items-center gap-3">
                  <div className="w-12 h-12 rounded-full bg-gradient-to-br from-cyan-400 to-blue-500 flex items-center justify-center text-white text-lg font-semibold">
                    {selectedClone?.emoji ? (
                      <span className="text-2xl">{selectedClone.emoji}</span>
                    ) : (
                      <span>{(selectedClone?.nickname || currentAgent?.name || 'Z').slice(0, 1)}</span>
                    )}
                  </div>
                  <div>
                    <div className="text-base font-semibold text-gray-900 dark:text-gray-100 flex items-center gap-2">
                      {selectedClone?.name || currentAgent?.name || 'ZCLAW'}
                      {selectedClone?.personality && (
                        <Badge variant="default" className="text-xs ml-1">
                          {getPersonalityById(selectedClone.personality)?.label || selectedClone.personality}
                        </Badge>
                      )}
                    </div>
                    <div className="text-sm text-gray-500 dark:text-gray-400">{selectedClone?.role || 'AI coworker'}</div>
                  </div>
                </div>
                {selectedClone ? (
                  isEditingAgent ? (
                    <div className="flex gap-2">
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={handleCancelEdit}
                        aria-label="Cancel edit"
                      >
                        Cancel
                      </Button>
                      <Button
                        variant="primary"
                        size="sm"
                        onClick={() => { handleSaveAgent().catch(silentErrorHandler('RightPanel')); }}
                        aria-label="Save edit"
                      >
                        Save
                      </Button>
                    </div>
                  ) : (
                    <Button
                      variant="outline"
                      size="sm"
                      onClick={handleStartEdit}
                      aria-label="Edit Agent"
                    >
                      Edit
                    </Button>
                  )
                ) : null}
              </div>
            </motion.div>

            <motion.div
              whileHover={cardHover}
              transition={defaultTransition}
              className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
            >
              <div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">About Me</div>
              {isEditingAgent && agentDraft ? (
                <div className="space-y-2">
                  <AgentInput label="Name" value={agentDraft.name} onChange={(value) => setAgentDraft({ ...agentDraft, name: value })} />
                  <AgentInput label="Role" value={agentDraft.role} onChange={(value) => setAgentDraft({ ...agentDraft, role: value })} />
                  <AgentInput label="Nickname" value={agentDraft.nickname} onChange={(value) => setAgentDraft({ ...agentDraft, nickname: value })} />
                  <AgentInput label="Model" value={agentDraft.model} onChange={(value) => setAgentDraft({ ...agentDraft, model: value })} />
                </div>
              ) : (
                <div className="space-y-3 text-sm">
                  <AgentRow label="Role" value={selectedClone?.role || '-'} />
                  <AgentRow label="Nickname" value={selectedClone?.nickname || '-'} />
                  <AgentRow label="Model" value={selectedClone?.model || currentModel} />
                  <AgentRow label="Emoji" value={selectedClone?.nickname?.slice(0, 1) || '🦞'} />
                </div>
              )}
            </motion.div>

            <motion.div
              whileHover={cardHover}
              transition={defaultTransition}
              className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
            >
              <div className="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">You in My Eyes</div>
              {isEditingAgent && agentDraft ? (
                <div className="space-y-2">
                  <AgentInput label="Name" value={agentDraft.userName} onChange={(value) => setAgentDraft({ ...agentDraft, userName: value })} />
                  <AgentInput label="Role" value={agentDraft.userRole} onChange={(value) => setAgentDraft({ ...agentDraft, userRole: value })} />
                  <AgentInput label="Scenarios" value={agentDraft.scenarios} onChange={(value) => setAgentDraft({ ...agentDraft, scenarios: value })} placeholder="coding, research" />
                  <AgentInput label="Workspace" value={agentDraft.workspaceDir} onChange={(value) => setAgentDraft({ ...agentDraft, workspaceDir: value })} />
                  <AgentToggle label="File Restriction" checked={agentDraft.restrictFiles} onChange={(value) => setAgentDraft({ ...agentDraft, restrictFiles: value })} />
                  <AgentToggle label="Opt-in Program" checked={agentDraft.privacyOptIn} onChange={(value) => setAgentDraft({ ...agentDraft, privacyOptIn: value })} />
                </div>
              ) : (
                <div className="space-y-3 text-sm">
                  <AgentRow label="Name" value={userNameDisplay} />
                  <AgentRow label="Addressing" value={userAddressing} />
                  <AgentRow label="Timezone" value={localTimezone} />
                  <div className="flex gap-4">
                    <div className="w-16 text-gray-500 dark:text-gray-400">Focus</div>
                    <div className="flex-1 flex flex-wrap gap-2">
                      {focusAreas.map((item) => (
                        <Badge key={item} variant="default">{item}</Badge>
                      ))}
                    </div>
                  </div>
                  <AgentRow label="Workspace" value={selectedClone?.workspaceDir || workspaceInfo?.path || '~/.openfang/zclaw-workspace'} />
                  <AgentRow label="Resolved" value={selectedClone?.workspaceResolvedPath || workspaceInfo?.resolvedPath || '-'} />
                  <AgentRow label="File Restriction" value={selectedClone?.restrictFiles ? 'Enabled' : 'Disabled'} />
                  <AgentRow label="Opt-in" value={selectedClone?.privacyOptIn ? 'Joined' : 'Not joined'} />
                </div>
              )}
            </motion.div>

            <motion.div
              whileHover={cardHover}
              transition={defaultTransition}
              className="rounded-xl border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 p-4 shadow-sm"
            >
              <div className="flex items-center justify-between mb-3">
                <div className="text-sm font-semibold text-gray-900 dark:text-gray-100">Bootstrap Files</div>
                <Badge variant={selectedClone?.bootstrapReady ? 'success' : 'default'}>
                  {selectedClone?.bootstrapReady ? 'Generated' : 'Not generated'}
                </Badge>
              </div>
              <div className="space-y-2 text-sm">
                {bootstrapFiles.length > 0 ? bootstrapFiles.map((file) => (
                  <div key={file.name} className="rounded-lg border border-gray-100 dark:border-gray-700 bg-gray-50 dark:bg-gray-700/50 px-3 py-2">
                    <div className="flex items-center justify-between gap-3">
                      <span className="font-medium text-gray-800 dark:text-gray-200">{file.name}</span>
                      <Badge variant={file.exists ? 'success' : 'error'}>
                        {file.exists ? 'Exists' : 'Missing'}
                      </Badge>
                    </div>
                    <div className="mt-1 text-xs text-gray-500 dark:text-gray-400 break-all">{file.path}</div>
                  </div>
                )) : (
                  <p className="text-sm text-gray-500 dark:text-gray-400">No bootstrap files generated for this Agent.</p>
                )}
              </div>
            </motion.div>
          </div>
        ) : activeTab === 'files' ? (
          <div className="p-4">
            <CodeSnippetPanel snippets={codeSnippets} />
          </div>
        ) : (
          <>
        {/* Gateway 连接状态 */}
        <motion.div
          whileHover={cardHover}
          transition={defaultTransition}
          className={`rounded-lg border p-3 ${connected ? 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800' : 'bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700'}`}
        >
          <div className="flex items-center justify-between mb-2">
            <div className="flex items-center gap-2">
              {connected ? (
                <Wifi className="w-4 h-4 text-green-600 dark:text-green-400" />
              ) : (
                <WifiOff className="w-4 h-4 text-gray-500 dark:text-gray-400" />
              )}
              <Badge variant={connected ? 'success' : 'default'}>
                Gateway {connected ? 'Connected' : connectionState === 'connecting' ? 'Connecting...' : connectionState === 'reconnecting' ? 'Reconnecting...' : 'Disconnected'}
              </Badge>
            </div>
            {connected && (
              <Button
                variant="ghost"
                size="sm"
                onClick={() => { loadUsageStats(); loadPluginStatus(); loadClones(); }}
                className="p-1 text-gray-500 hover:text-orange-500"
                title="Refresh data"
                aria-label="Refresh data"
              >
                <RefreshCw className="w-3.5 h-3.5" />
              </Button>
            )}
          </div>
          <div className="space-y-1 text-xs">
            <div className="flex justify-between">
              <span className="text-gray-500">地址</span>
              <span className="text-gray-700 font-mono">{gatewayUrl}</span>
            </div>
            {gatewayVersion && (
              <div className="flex justify-between">
                <span className="text-gray-500">版本</span>
                <span className="text-gray-700">{gatewayVersion}</span>
              </div>
            )}
            <div className="flex justify-between">
              <span className="text-gray-500">当前模型</span>
              <span className="text-orange-600 font-medium">{currentModel}</span>
            </div>
          </div>
          {!connected && connectionState !== 'connecting' && (
            <div className="mt-2">
              <Button
                variant="primary"
                size="sm"
                onClick={handleReconnect}
                className="w-full"
              >
                Connect Gateway
              </Button>
            </div>
          )}
          {error && (
            <p className="mt-2 text-xs text-red-500 truncate" title={error}>{error}</p>
          )}
        </motion.div>

        {/* 当前会话 */}
        <motion.div
          whileHover={cardHover}
          transition={defaultTransition}
          className="bg-gray-50 rounded-lg border border-gray-100 p-3"
        >
          <h3 className="text-xs font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
            <MessageSquare className="w-3.5 h-3.5" />
            当前会话
          </h3>
          <div className="space-y-1.5 text-xs">
            <div className="flex justify-between">
              <span className="text-gray-500">用户消息</span>
              <span className="font-medium text-gray-900">{userMsgCount}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">助手回复</span>
              <span className="font-medium text-gray-900">{assistantMsgCount}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">工具调用</span>
              <span className="font-medium text-gray-900">{toolCallCount}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">总消息数</span>
              <span className="font-medium text-orange-600">{messages.length}</span>
            </div>
          </div>
        </motion.div>

        {/* 分身 */}
        <motion.div
          whileHover={cardHover}
          transition={defaultTransition}
          className="bg-gray-50 rounded-lg border border-gray-100 p-3"
        >
          <h3 className="text-xs font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
            <Bot className="w-3.5 h-3.5" />
            分身状态
          </h3>
          {clones.length > 0 ? (
            <div className="space-y-1.5">
              {clones.slice(0, 5).map(c => (
                <div key={c.id} className="flex items-center gap-2 text-xs">
                  <div className="w-5 h-5 bg-gradient-to-br from-orange-400 to-red-500 rounded-md flex items-center justify-center text-white text-[10px]">
                    <Bot className="w-3 h-3" />
                  </div>
                  <span className="text-gray-700 truncate">{c.name}</span>
                </div>
              ))}
              {clones.length > 5 && (
                <p className="text-xs text-gray-500">+{clones.length - 5} 个分身</p>
              )}
            </div>
          ) : (
            <p className="text-xs text-gray-500">
              {connected ? '暂无分身，在左侧栏创建' : '连接后可用'}
            </p>
          )}
        </motion.div>

        {/* 用量统计 */}
        {usageStats && (
          <motion.div
            whileHover={cardHover}
            transition={defaultTransition}
            className="bg-gray-50 rounded-lg border border-gray-100 p-3"
          >
            <h3 className="text-xs font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
              <BarChart3 className="w-3.5 h-3.5" />
              用量统计
            </h3>
            <div className="space-y-1.5 text-xs">
              <div className="flex justify-between">
                <span className="text-gray-500">总会话数</span>
                <span className="font-medium text-gray-900">{usageStats.totalSessions}</span>
              </div>
              <div className="flex justify-between">
                <span className="text-gray-500">总消息数</span>
                <span className="font-medium text-gray-900">{usageStats.totalMessages}</span>
              </div>
              <div className="flex justify-between">
                <span className="text-gray-500">总 Token</span>
                <span className="font-medium text-gray-900">{usageStats.totalTokens.toLocaleString()}</span>
              </div>
            </div>
          </motion.div>
        )}

        {/* 插件状态 */}
        {pluginStatus.length > 0 && (
          <motion.div
            whileHover={cardHover}
            transition={defaultTransition}
            className="bg-gray-50 rounded-lg border border-gray-100 p-3"
          >
            <h3 className="text-xs font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
              <Plug className="w-3.5 h-3.5" />
              插件 ({pluginStatus.length})
            </h3>
            <div className="space-y-1 text-xs">
              {pluginStatus.map((p: PluginStatus, i: number) => (
                <div key={i} className="flex justify-between">
                  <span className="text-gray-600 truncate">{p.name || p.id}</span>
                  <span className={p.status === 'active' ? 'text-green-600' : 'text-gray-500'}>
                    {p.status === 'active' ? '运行中' : '已停止'}
                  </span>
                </div>
              ))}
            </div>
          </motion.div>
        )}

        {/* 系统信息 */}
        <motion.div
          whileHover={cardHover}
          transition={defaultTransition}
          className="bg-gray-50 rounded-lg border border-gray-100 p-3"
        >
          <h3 className="text-xs font-semibold text-gray-700 mb-2 flex items-center gap-1.5">
            <Cpu className="w-3.5 h-3.5" />
            运行概览
          </h3>
          <div className="space-y-1.5 text-xs">
            <div className="flex justify-between">
              <span className="text-gray-500">连接状态</span>
              <span className="text-gray-700">{runtimeSummary}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">Gateway 版本</span>
              <span className="text-gray-700">{gatewayVersion || '-'}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">已加载分身</span>
              <span className="text-gray-700">{clones.length}</span>
            </div>
            <div className="flex justify-between">
              <span className="text-gray-500">已加载插件</span>
              <span className="text-gray-700">{pluginStatus.length}</span>
            </div>
          </div>
        </motion.div>
          </>
        )}
      </div>

    </aside>
  );
}

function AgentRow({ label, value }: { label: string; value: string }) {
  return (
    <div className="flex gap-4">
      <div className="w-16 text-gray-500">{label}</div>
      <div className="flex-1 text-gray-700 break-all">{value}</div>
    </div>
  );
}

type AgentDraft = {
  name: string;
  role: string;
  nickname: string;
  model: string;
  scenarios: string;
  workspaceDir: string;
  userName: string;
  userRole: string;
  restrictFiles: boolean;
  privacyOptIn: boolean;
};

function createAgentDraft(
  clone: {
    name: string;
    role?: string;
    nickname?: string;
    model?: string;
    scenarios?: string[];
    workspaceDir?: string;
    userName?: string;
    userRole?: string;
    restrictFiles?: boolean;
    privacyOptIn?: boolean;
  },
  currentModel: string
): AgentDraft {
  return {
    name: clone.name || '',
    role: clone.role || '',
    nickname: clone.nickname || '',
    model: clone.model || currentModel,
    scenarios: clone.scenarios?.join(', ') || '',
    workspaceDir: clone.workspaceDir || '~/.openfang/zclaw-workspace',
    userName: clone.userName || '',
    userRole: clone.userRole || '',
    restrictFiles: clone.restrictFiles ?? true,
    privacyOptIn: clone.privacyOptIn ?? false,
  };
}

function AgentInput({
  label,
  value,
  onChange,
  placeholder,
}: {
  label: string;
  value: string;
  onChange: (value: string) => void;
  placeholder?: string;
}) {
  return (
    <label className="block">
      <div className="text-xs text-gray-500 mb-1">{label}</div>
      <input
        type="text"
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        className="w-full text-sm border border-gray-200 rounded-lg px-3 py-2 focus:outline-none"
      />
    </label>
  );
}

function AgentToggle({
  label,
  checked,
  onChange,
}: {
  label: string;
  checked: boolean;
  onChange: (value: boolean) => void;
}) {
  return (
    <label className="flex items-center justify-between text-sm text-gray-700 border border-gray-100 rounded-lg px-3 py-2">
      <span>{label}</span>
      <input type="checkbox" checked={checked} onChange={(e) => onChange(e.target.checked)} />
    </label>
  );
}
