import { useState, useEffect } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { ArrowLeft, Save, X, Database, CheckSquare, Square, FolderOpen } from 'lucide-react'
import toast from 'react-hot-toast'
import { agentsApi } from '../api/agents'
import { knowledgeApi } from '../api/knowledge'
import { Button, Input, Textarea, Card, PageHeader, Spinner, Tabs } from '../components/ui'
import { clsx } from '../lib/clsx'
import DirPickerModal from '../components/DirPickerModal'

// ── Tool tag editor (same as AgentImport) ────────────────────────

function ToolTagEditor({ tools, onChange }: { tools: string[]; onChange: (t: string[]) => void }) {
  const [input, setInput] = useState('')

  function add() {
    const v = input.trim()
    if (v && !tools.includes(v)) onChange([...tools, v])
    setInput('')
  }

  return (
    <div>
      <div className="flex flex-wrap gap-1.5 mb-2 min-h-[2rem]">
        {tools.map(t => (
          <span key={t} className="inline-flex items-center gap-1 text-xs bg-gray-100 text-gray-700 px-2 py-1 rounded-full">
            {t}
            <button type="button" onClick={() => onChange(tools.filter(x => x !== t))}
              className="text-gray-400 hover:text-red-500 transition-colors">
              <X size={10} />
            </button>
          </span>
        ))}
      </div>
      <div className="flex gap-2">
        <input value={input} onChange={e => setInput(e.target.value)}
          onKeyDown={e => e.key === 'Enter' && (e.preventDefault(), add())}
          placeholder="输入工具名，回车添加"
          className="flex-1 rounded-lg border border-gray-300 px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500" />
        <button type="button" onClick={add} disabled={!input.trim()}
          className="px-3 py-1.5 rounded-lg bg-gray-100 text-gray-600 text-sm hover:bg-gray-200 disabled:opacity-40 transition-colors">
          添加
        </button>
      </div>
    </div>
  )
}

// ── Constants ─────────────────────────────────────────────────────

const MODEL_MAP: Record<string, string[]> = {
  'claude-code': ['sonnet', 'opus', 'haiku'],
  anthropic:     ['claude-sonnet-4-6', 'claude-opus-4-7', 'claude-haiku-4-5-20251001'],
  dashscope:     ['qwen3-max-2026-01-23', 'qwen-max', 'qwen-plus', 'qwen-turbo'],
  deepseek:      ['deepseek-chat', 'deepseek-reasoner'],
  openai:        ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo'],
  ollama:        ['qwen2.5:7b', 'qwen2.5:32b', 'llama3.2:3b', 'mistral:7b'],
}

const TABS = [
  { id: 'basic',    label: '基本设置' },
  { id: 'model',    label: '模型配置' },
  { id: 'behavior', label: '行为配置' },
  { id: 'memory',   label: '记忆 & 运行时' },
  { id: 'guard',    label: '验收 & 安全' },
  { id: 'tools',    label: '工具列表' },
  { id: 'prompt',   label: '系统提示词' },
  { id: 'kb',       label: '知识库' },
]

// ── Page ──────────────────────────────────────────────────────────

export default function AgentEdit() {
  const { agentId } = useParams<{ agentId: string }>()
  const navigate = useNavigate()
  const qc = useQueryClient()
  const [tab, setTab] = useState('basic')
  const [ready, setReady] = useState(false)

  // basic
  const [name, setName]               = useState('')
  const [description, setDescription] = useState('')
  const [agentType, setAgentType]     = useState('react')
  const [agentDir, setAgentDir]       = useState('')
  const [workDir, setWorkDir]         = useState('')
  const [sourceDir, setSourceDir]     = useState('')
  const [runDir, setRunDir]           = useState('')
  // which dir picker is open: 'work' | 'source' | 'run' | null
  const [dirPickerFor, setDirPickerFor] = useState<'work' | 'source' | 'run' | null>(null)

  // model
  const [provider, setProvider]       = useState('')
  const [modelName, setModelName]     = useState('')
  const [temperature, setTemperature] = useState('0.7')
  const [maxTokens, setMaxTokens]     = useState('4096')
  const [baseUrl, setBaseUrl]         = useState('')

  // behavior
  const [reactMaxSteps, setReactMaxSteps] = useState('20')
  const [toolTimeout, setToolTimeout]     = useState('60')
  const [thinkTimeout, setThinkTimeout]   = useState('120')
  const [progressDiscipline, setProgressDiscipline] = useState(false)
  const [nativeToolCalls, setNativeToolCalls] = useState(false)

  // memory & runtime
  const [memoryEnabled, setMemoryEnabled] = useState(false)
  const [memorySize, setMemorySize]       = useState('20')
  const [memoryTtl, setMemoryTtl]         = useState('3600')
  const [runtimeEngine, setRuntimeEngine] = useState('cek')
  const [costBudget, setCostBudget]       = useState('0.5')

  // guard (验收 & 安全) — agent-level output validation + tool safety
  const [guardEnabled, setGuardEnabled]             = useState(false)
  const [guardValidator, setGuardValidator]         = useState('')
  const [guardRetry, setGuardRetry]                 = useState('0')
  const [guardFallback, setGuardFallback]           = useState('error')
  const [guardBlockDangerous, setGuardBlockDangerous] = useState(true)
  const [guardHighRiskConfirm, setGuardHighRiskConfirm] = useState(false)
  const [guardMaxOutput, setGuardMaxOutput]         = useState('0')

  // tools & prompt
  const [localTools, setLocalTools]     = useState<string[]>([])
  const [systemPrompt, setSystemPrompt] = useState('')

  // sub-agents (multi-agent orchestrator). Read-only view: each entry maps a
  // sub-agent name to { tool: call_*, config: ./path.yml } or an inline def.
  const [subAgents, setSubAgents] = useState<Record<string, unknown>>({})
  // Clicking a sub-agent loads & shows its config file. Cache keyed by name.
  const [openSub, setOpenSub] = useState<string | null>(null)
  const [subConfigs, setSubConfigs] = useState<Record<string, {
    loading: boolean; content?: string; path?: string | null; error?: string
  }>>({})

  const toggleSub = async (name: string) => {
    if (openSub === name) { setOpenSub(null); return }
    setOpenSub(name)
    if (subConfigs[name]?.content !== undefined || subConfigs[name]?.error) return
    setSubConfigs(p => ({ ...p, [name]: { loading: true } }))
    try {
      const r = await agentsApi.subAgentConfig(agentId!, name)
      setSubConfigs(p => ({ ...p, [name]: { loading: false, content: r.content, path: r.path } }))
    } catch (e) {
      const msg = (e as Error)?.message || String(e)
      setSubConfigs(p => ({ ...p, [name]: { loading: false, error: msg } }))
    }
  }

  // knowledge bases
  const [linkedKBs, setLinkedKBs]         = useState<string[]>([])
  const [kbSearchMode, setKbSearchMode]   = useState('bm25')

  const { data: agent, isLoading } = useQuery({
    queryKey: ['agents', agentId],
    queryFn: () => agentsApi.get(agentId!),
    enabled: !!agentId,
  })

  // Populate form once agent loads
  useEffect(() => {
    if (!agent || ready) return
    const cfg = agent.config as Record<string, unknown>
    const m   = (cfg.model   as Record<string, unknown>) ?? {}
    const r   = (cfg.react   as Record<string, unknown>) ?? {}
    const mem = (cfg.memory  as Record<string, unknown>) ?? {}
    const rt  = (cfg.runtime as Record<string, unknown>) ?? {}
    const mcp = (cfg.mcp     as Record<string, unknown>) ?? {}

    setName(agent.name ?? '')
    setDescription(agent.description ?? '')
    setAgentType((cfg.type as string) ?? 'react')
    setAgentDir(agent.agent_dir ?? '')
    setWorkDir(agent.work_dir ?? '')
    setSourceDir(agent.source_dir ?? '')
    setRunDir(agent.run_dir ?? '')

    setProvider((m.provider as string) ?? '')
    setModelName((m.name as string) ?? '')
    setTemperature(String(m.temperature ?? 0.7))
    setMaxTokens(String(m.maxTokens ?? 4096))
    setBaseUrl((m.baseUrl as string) ?? '')

    setReactMaxSteps(String(r.maxSteps    ?? 20))
    setToolTimeout(String(r.toolTimeout   ?? 60))
    setThinkTimeout(String(r.thinkTimeout ?? 120))
    setProgressDiscipline(Boolean(r.progressDiscipline))
    setNativeToolCalls(Boolean(r.nativeToolCalls))

    setMemoryEnabled(Boolean(mem.enabled))
    setMemorySize(String(mem.size ?? 20))
    setMemoryTtl(String(mem.ttl   ?? 3600))

    setRuntimeEngine((rt.engine as string) ?? 'cek')
    setCostBudget(String(rt.costBudget ?? 0.5))

    const g = (cfg.guard as Record<string, unknown>) ?? {}
    setGuardEnabled(Object.keys(g).length > 0)
    setGuardValidator((g.validator as string) ?? '')
    setGuardRetry(String(g.retry ?? 0))
    setGuardFallback((g.fallback as string) ?? 'error')
    setGuardBlockDangerous(g.dangerousCommandBlock !== false)   // default true
    setGuardHighRiskConfirm(Boolean(g.highRiskConfirmation))
    setGuardMaxOutput(String(g.maxOutputLength ?? 0))

    setLocalTools((mcp.localTools as string[]) ?? [])
    setSystemPrompt((cfg.systemPrompt as string) ?? '')
    // Compiler accepts both `subAgents` (camelCase) and `sub_agents`.
    setSubAgents(
      (cfg.subAgents as Record<string, unknown>) ??
      (cfg.sub_agents as Record<string, unknown>) ??
      {},
    )
    setLinkedKBs(agent.kb_ids ?? [])
    setKbSearchMode(agent.kb_search_mode ?? 'bm25')
    setReady(true)
  }, [agent, ready])

  const saveMutation = useMutation({
    mutationFn: () => {
      const cfg = { ...(agent!.config as Record<string, unknown>) }
      cfg.name        = name.trim()
      cfg.description = description
      cfg.type        = agentType
      cfg.systemPrompt = systemPrompt
      cfg.model = {
        ...((cfg.model as object) ?? {}),
        provider, name: modelName,
        temperature: parseFloat(temperature) || 0.7,
        maxTokens:   parseInt(maxTokens) || 4096,
        ...(baseUrl ? { baseUrl } : {}),
      }
      cfg.react = {
        ...((cfg.react as object) ?? {}),
        maxSteps:     parseInt(reactMaxSteps) || 20,
        toolTimeout:  parseInt(toolTimeout)   || 60,
        thinkTimeout: parseInt(thinkTimeout)  || 120,
        progressDiscipline,
        nativeToolCalls,
      }
      cfg.memory = {
        ...((cfg.memory as object) ?? {}),
        enabled: memoryEnabled,
        size:    parseInt(memorySize) || 20,
        ttl:     parseInt(memoryTtl)  || 3600,
      }
      cfg.runtime = {
        ...((cfg.runtime as object) ?? {}),
        engine:     runtimeEngine,
        costBudget: parseFloat(costBudget) || 0.5,
      }
      cfg.mcp = { ...((cfg.mcp as object) ?? {}), localTools }

      if (guardEnabled) {
        cfg.guard = {
          ...((cfg.guard as object) ?? {}),
          ...(guardValidator.trim() ? { validator: guardValidator.trim() } : {}),
          retry:                 parseInt(guardRetry) || 0,
          fallback:              guardFallback,
          dangerousCommandBlock: guardBlockDangerous,
          highRiskConfirmation:  guardHighRiskConfirm,
          maxOutputLength:       parseInt(guardMaxOutput) || 0,
        }
      } else {
        delete cfg.guard
      }

      return agentsApi.update(agentId!, {
        config:     cfg,
        agent_dir:  agentDir,
        work_dir:   workDir,
        source_dir: sourceDir,
        run_dir:    runDir,
        changelog: `Web UI 编辑 — ${new Date().toLocaleString('zh-CN')}`,
      })
    },
    onSuccess: () => {
      toast.success('配置已保存，新版本生效')
      qc.invalidateQueries({ queryKey: ['agents', agentId] })
      qc.invalidateQueries({ queryKey: ['agents'] })
      navigate(`/chat/${agentId}`)
    },
    onError: () => toast.error('保存失败，请检查配置'),
  })

  // KB queries & mutation
  const { data: kbData } = useQuery({
    queryKey: ['knowledge-bases'],
    queryFn: knowledgeApi.list,
  })
  const allKBs = kbData?.items ?? []

  const kbMutation = useMutation({
    mutationFn: () => agentsApi.updateKBs(agentId!, linkedKBs, kbSearchMode),
    onSuccess: () => {
      toast.success('知识库绑定已更新')
      qc.invalidateQueries({ queryKey: ['agents', agentId] })
      qc.invalidateQueries({ queryKey: ['agent-knowledge', agentId] })
    },
    onError: () => toast.error('知识库绑定更新失败'),
  })

  if (isLoading) {
    return (
      <div className="flex justify-center items-center h-64">
        <Spinner size={32} />
      </div>
    )
  }

  return (
    <div className="p-8 max-w-4xl mx-auto">
      <div className="flex items-center gap-3 mb-6">
        <button onClick={() => navigate(-1)} className="text-gray-400 hover:text-gray-700 transition-colors">
          <ArrowLeft size={18} />
        </button>
        <PageHeader
          title={`编辑：${agent?.name ?? ''}`}
          description={`v${agent?.current_version} · 保存后自动创建新版本`}
        />
      </div>

      <Card>
        <Tabs
          tabs={(() => {
            if (Object.keys(subAgents).length === 0) return TABS
            // Insert the read-only 子智能体 tab right AFTER 工具列表 (sub-agents
            // are compiled into call_* tools, so they belong next to tools).
            // Fall back to before 知识库 if the tools tab is ever renamed.
            const after = TABS.findIndex(t => t.id === 'tools')
            const i = after >= 0 ? after + 1 : TABS.findIndex(t => t.id === 'kb')
            return [...TABS.slice(0, i), { id: 'subagents', label: '子智能体' }, ...TABS.slice(i)]
          })()}
          active={tab}
          onChange={setTab}
        />

        {/* ── 基本设置 ── */}
        {tab === 'basic' && (
          <div className="space-y-4 max-w-lg">
            <Input label="智能体名称" value={name} onChange={e => setName(e.target.value)} />
            <Textarea label="描述" rows={3} value={description} onChange={e => setDescription(e.target.value)} />
            <div>
              <label className="block text-xs font-medium text-gray-700 mb-1">智能体类型</label>
              <select value={agentType} onChange={e => setAgentType(e.target.value)}
                className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
                <option value="react">ReAct 智能体（工具调用 + 多步推理）</option>
                <option value="conversation">对话助手（多轮对话）</option>
                <option value="compose">流水线（多智能体串联）</option>
                <option value="groupchat">多智能体群聊</option>
              </select>
            </div>
            {/* ── 三目录配置 ── */}
            <div className="space-y-3 rounded-xl border border-indigo-100 bg-indigo-50/40 p-4">
              <p className="text-xs font-semibold text-indigo-700 uppercase tracking-wide">目录配置</p>

              {/* source_dir */}
              <DirField
                label="① 数据来源目录"
                hint="只读输入数据所在位置；智能体启动时自动提示从此处读取文件"
                value={sourceDir}
                onChange={setSourceDir}
                onBrowse={() => setDirPickerFor('source')}
                placeholder="/Users/me/papers"
                color="blue"
              />

              {/* work_dir */}
              <DirField
                label="② 工作产物目录"
                hint="Bash 工具的初始路径；智能体在此写入最终交付成果"
                value={workDir}
                onChange={setWorkDir}
                onBrowse={() => setDirPickerFor('work')}
                placeholder="/Users/me/Documents/my-project"
                color="amber"
              />

              {/* run_dir */}
              <DirField
                label="③ 运行日志目录"
                hint="每次对话的 run_*/traces/中间产物落在这里；留空则自动使用【工作产物目录】"
                value={runDir}
                onChange={setRunDir}
                onBrowse={() => setDirPickerFor('run')}
                placeholder="留空 = 自动（工作产物目录 + /workspace）"
                color="green"
              />
            </div>
            <Input
              label="智能体数据目录（高级）"
              value={agentDir}
              onChange={e => setAgentDir(e.target.value)}
              placeholder="如 agentexample/research67"
              hint="Pack 或模板的系统目录，用于加载子智能体配置。普通用户无需填写。"
            />
          </div>
        )}

        {/* ── 模型配置 ── */}
        {tab === 'model' && (
          <div className="space-y-4 max-w-lg">
            <div>
              <label className="block text-xs font-medium text-gray-700 mb-1">AI 提供商</label>
              <select value={provider} onChange={e => { setProvider(e.target.value); setModelName('') }}
                className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
                <option value="">选择提供商</option>
                {Object.keys(MODEL_MAP).map(p => <option key={p} value={p}>{p}</option>)}
              </select>
            </div>
            {provider && (
              <div>
                <label className="block text-xs font-medium text-gray-700 mb-1">模型</label>
                <select value={modelName} onChange={e => setModelName(e.target.value)}
                  className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
                  <option value="">选择模型</option>
                  {(MODEL_MAP[provider] ?? []).map(m => <option key={m} value={m}>{m}</option>)}
                </select>
              </div>
            )}
            <div className="grid grid-cols-2 gap-4">
              <Input label="Temperature" type="number" value={temperature} onChange={e => setTemperature(e.target.value)} />
              <Input label="Max Tokens"  type="number" value={maxTokens}   onChange={e => setMaxTokens(e.target.value)} />
            </div>
            <Input label="Base URL（Ollama / 自定义端点）" value={baseUrl}
              onChange={e => setBaseUrl(e.target.value)} placeholder="http://localhost:11434" />
          </div>
        )}

        {/* ── 行为配置 ── */}
        {tab === 'behavior' && (
          <div className="space-y-4 max-w-lg">
            <p className="text-xs text-gray-500">以下参数控制 ReAct 循环的执行行为。</p>
            <div className="grid grid-cols-3 gap-4">
              <Input label="最大步数"     type="number" value={reactMaxSteps} onChange={e => setReactMaxSteps(e.target.value)} hint="每次对话最多执行的工具调用轮次" />
              <Input label="工具超时（秒）" type="number" value={toolTimeout}   onChange={e => setToolTimeout(e.target.value)}   hint="单次工具调用最长等待时间" />
              <Input label="思考超时（秒）" type="number" value={thinkTimeout}  onChange={e => setThinkTimeout(e.target.value)}  hint="LLM 单次生成最长时间" />
            </div>
            <label className="flex items-start gap-2 cursor-pointer pt-2">
              <input type="checkbox" className="mt-0.5" checked={progressDiscipline}
                     onChange={e => setProgressDiscipline(e.target.checked)} />
              <span className="text-sm">
                <span className="font-medium text-gray-800">进度纪律（PROGRESS.md）</span>
                <span className="block text-xs text-gray-500 mt-0.5">
                  多步任务自动维护工作目录里的 PROGRESS.md 待办清单（建/读/逐项打勾、不重做、
                  不做完不收尾）——防上下文被裁剪后"忘记进度、工具调用乱跳/重做"。建议给
                  审稿、批改、改论文、跑实验等多步产文件的智能体开启；纯问答/单步任务可不开。
                </span>
              </span>
            </label>
            <label className="flex items-start gap-2 cursor-pointer pt-2">
              <input type="checkbox" className="mt-0.5" checked={nativeToolCalls}
                     onChange={e => setNativeToolCalls(e.target.checked)} />
              <span className="text-sm">
                <span className="font-medium text-gray-800">原生 function-calling（实验）</span>
                <span className="block text-xs text-gray-500 mt-0.5">
                  用模型的结构化 tool_calls 执行工具，取代"让模型手写 JSON、平台正则抠"——
                  根治工具不执行、参数名漂移（path/file_path）、裸字符串等问题。
                  仅对支持的模型生效（qwen / openai / deepseek 等）；claude-code 已走原生车道。
                  不支持的模型自动回退文本模式。建议给 qwen-plus 等开启。
                </span>
              </span>
            </label>
          </div>
        )}

        {/* ── 记忆 & 运行时 ── */}
        {tab === 'memory' && (
          <div className="space-y-6 max-w-lg">
            <div>
              <h3 className="text-xs font-semibold text-gray-700 uppercase tracking-wide mb-3">记忆配置</h3>
              <div className="space-y-3">
                <label className="flex items-center gap-3 cursor-pointer">
                  <input type="checkbox" checked={memoryEnabled} onChange={e => setMemoryEnabled(e.target.checked)}
                    className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
                  <span className="text-sm text-gray-700">启用长期记忆</span>
                </label>
                {memoryEnabled && (
                  <div className="grid grid-cols-2 gap-4 pl-7">
                    <Input label="记忆条数上限" type="number" value={memorySize} onChange={e => setMemorySize(e.target.value)} hint="超过上限时自动淘汰旧记忆" />
                    <Input label="TTL（秒）"    type="number" value={memoryTtl}  onChange={e => setMemoryTtl(e.target.value)}  hint="0 = 永不过期" />
                  </div>
                )}
              </div>
            </div>
            <div>
              <h3 className="text-xs font-semibold text-gray-700 uppercase tracking-wide mb-3">运行时引擎</h3>
              <div className="space-y-3">
                <div>
                  <label className="block text-xs font-medium text-gray-700 mb-1">执行引擎</label>
                  <select value={runtimeEngine} onChange={e => setRuntimeEngine(e.target.value)}
                    className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
                    <option value="cek">CEK Machine（带成本监控 + 循环检测）</option>
                    <option value="recursive">Recursive（简单递归，无开销）</option>
                    <option value="adaptive">Adaptive（自动选择）</option>
                  </select>
                </div>
                <Input label="费用上限（USD）" type="number" value={costBudget}
                  onChange={e => setCostBudget(e.target.value)} hint="超过此金额后自动暂停，0 = 不限制" />
              </div>
            </div>
          </div>
        )}

        {/* ── 验收 & 安全（Guard） ── */}
        {tab === 'guard' && (
          <div className="space-y-6 max-w-lg">
            <label className="flex items-center gap-3 cursor-pointer">
              <input type="checkbox" checked={guardEnabled} onChange={e => setGuardEnabled(e.target.checked)}
                className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
              <span className="text-sm font-medium text-gray-800">启用验收 Guard（对智能体输出做校验 + 工具安全护栏）</span>
            </label>

            {guardEnabled && (
              <>
                <div>
                  <h3 className="text-xs font-semibold text-gray-700 uppercase tracking-wide mb-3">输出验收</h3>
                  <div className="space-y-3">
                    <Textarea
                      label="验收表达式（validator）"
                      rows={2}
                      value={guardValidator}
                      onChange={e => setGuardValidator(e.target.value)}
                      placeholder={'例：\'评审结论\' in x  或  \'acceptance_probability\' in x'}
                      hint="对输出 x 求值的安全表达式（AST 白名单），返回真才算通过；留空 = 不校验内容"
                    />
                    <div className="grid grid-cols-2 gap-4">
                      <Input label="失败重试次数" type="number" value={guardRetry}
                        onChange={e => setGuardRetry(e.target.value)} hint="校验不过时重跑的次数" />
                      <div>
                        <label className="block text-xs font-medium text-gray-700 mb-1">重试耗尽后</label>
                        <select value={guardFallback} onChange={e => setGuardFallback(e.target.value)}
                          className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500">
                          <option value="error">报错中止（error）</option>
                          <option value="last">返回最后一次输出（last）</option>
                        </select>
                      </div>
                    </div>
                  </div>
                </div>

                <div>
                  <h3 className="text-xs font-semibold text-gray-700 uppercase tracking-wide mb-3">工具安全护栏</h3>
                  <div className="space-y-3">
                    <label className="flex items-center gap-3 cursor-pointer">
                      <input type="checkbox" checked={guardBlockDangerous} onChange={e => setGuardBlockDangerous(e.target.checked)}
                        className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
                      <span className="text-sm text-gray-700">拦截危险命令（rm -rf、sudo、curl|sh 等）</span>
                    </label>
                    <label className="flex items-center gap-3 cursor-pointer">
                      <input type="checkbox" checked={guardHighRiskConfirm} onChange={e => setGuardHighRiskConfirm(e.target.checked)}
                        className="w-4 h-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" />
                      <span className="text-sm text-gray-700">高危操作需人工确认</span>
                    </label>
                    <Input label="工具输出最大长度（字节，0 = 不限）" type="number" value={guardMaxOutput}
                      onChange={e => setGuardMaxOutput(e.target.value)} hint="超长则截断，防止上下文爆掉" />
                  </div>
                </div>

                <p className="text-xs text-gray-400 bg-gray-50 rounded-lg px-3 py-2">
                  验收 Guard 在编译期生效（lambdagent Guard 构造）。审稿场景常用：让结论必须含「评审结论」或「接受概率」，否则自动重审。
                </p>
              </>
            )}
          </div>
        )}

        {/* ── 工具列表 ── */}
        {tab === 'tools' && (
          <div className="max-w-2xl space-y-3">
            <p className="text-xs text-gray-500">点击 ✕ 移除工具，在输入框中填写工具名并回车添加。</p>
            <ToolTagEditor tools={localTools} onChange={setLocalTools} />
            {localTools.length === 0 && (
              <p className="text-xs text-amber-600 bg-amber-50 rounded-lg px-3 py-2">
                工具列表为空，智能体将不能调用任何工具。
              </p>
            )}
          </div>
        )}

        {/* ── 子智能体 ── */}
        {tab === 'subagents' && (
          <div className="max-w-2xl space-y-3">
            <p className="text-xs text-gray-500">
              该智能体是<strong>多智能体协调者</strong>。下列子智能体在运行时被编译为
              <code className="mx-1 px-1 bg-gray-100 rounded">call_*</code>工具，由协调者按需调度。
              子智能体配置在 Pack 的 YAML 中定义，此处为只读视图。
            </p>
            <div className="space-y-2">
              {Object.entries(subAgents).map(([key, raw]) => {
                const v = (raw ?? {}) as Record<string, unknown>
                const tool   = (v.tool as string) || `call_${key}`
                const config = (v.config as string) || ''
                const model  = (v.model as Record<string, unknown>) || undefined
                const desc   = (v.description as string) || ''
                const open   = openSub === key
                const sc     = subConfigs[key]
                return (
                  <div key={key} className="rounded-lg border border-gray-200 bg-white overflow-hidden">
                    <button
                      type="button"
                      onClick={() => toggleSub(key)}
                      className="w-full text-left px-4 py-3 hover:bg-gray-50 transition-colors"
                    >
                      <div className="flex items-center justify-between gap-2">
                        <span className="flex items-center gap-1.5 text-sm font-semibold text-gray-900">
                          <span className={clsx('text-gray-400 transition-transform', open && 'rotate-90')}>▶</span>
                          {key}
                        </span>
                        <span className="inline-flex items-center text-xs font-mono bg-indigo-50 text-indigo-600 border border-indigo-200 px-1.5 py-0.5 rounded">
                          {tool}
                        </span>
                      </div>
                      {desc && <p className="text-xs text-gray-500 mt-1 ml-5">{desc}</p>}
                      {config && (
                        <p className="text-xs text-gray-400 mt-1 ml-5 font-mono break-all">📄 {config}</p>
                      )}
                      {model && (
                        <p className="text-xs text-gray-400 mt-1 ml-5">
                          模型：{(model.provider as string) ?? '—'} · {(model.name as string) ?? '—'}
                        </p>
                      )}
                    </button>

                    {open && (
                      <div className="border-t border-gray-100 bg-gray-50">
                        {sc?.loading && (
                          <p className="text-xs text-gray-400 px-4 py-3">加载配置文件中…</p>
                        )}
                        {sc?.error && (
                          <p className="text-xs text-red-600 px-4 py-3">
                            无法读取配置文件：{sc.error}
                          </p>
                        )}
                        {sc?.content !== undefined && (
                          <div>
                            {sc.path && (
                              <p className="text-[11px] text-gray-400 font-mono break-all px-4 pt-2">
                                {sc.path}
                              </p>
                            )}
                            <pre className="text-xs leading-relaxed text-gray-800 font-mono whitespace-pre-wrap px-4 py-3 max-h-[480px] overflow-auto">
                              {sc.content}
                            </pre>
                          </div>
                        )}
                      </div>
                    )}
                  </div>
                )
              })}
            </div>
            <p className="text-xs text-gray-400">
              共 {Object.keys(subAgents).length} 个子智能体。如需修改，请编辑对应 Pack 的 YAML 后重新安装。
            </p>
          </div>
        )}

        {/* ── 系统提示词 ── */}
        {tab === 'prompt' && (
          <div className="max-w-2xl">
            <Textarea label="系统提示词" rows={16} value={systemPrompt}
              onChange={e => setSystemPrompt(e.target.value)} />
          </div>
        )}

        {/* ── 知识库 ── */}
        {tab === 'kb' && (
          <div className="space-y-5 max-w-lg">
            <p className="text-xs text-gray-500">
              绑定知识库后，每次对话前会自动检索相关内容注入提示词（RAG 增强）。
              知识库变更立即保存，无需点击"保存并生效"。
            </p>

            {/* Search mode */}
            <div>
              <label className="block text-xs font-medium text-gray-700 mb-1">检索模式</label>
              <select
                value={kbSearchMode}
                onChange={e => setKbSearchMode(e.target.value)}
                className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500"
              >
                <option value="bm25">BM25 关键词检索（推荐）</option>
                <option value="pageindex">PageIndex 页面级检索</option>
              </select>
            </div>

            {/* KB multi-select */}
            <div>
              <label className="block text-xs font-medium text-gray-700 mb-2">
                可用知识库
                {linkedKBs.length > 0 && (
                  <span className="ml-2 text-indigo-600">（已绑定 {linkedKBs.length} 个）</span>
                )}
              </label>
              {allKBs.length === 0 ? (
                <div className="rounded-lg border border-dashed border-gray-200 p-6 text-center text-sm text-gray-400">
                  <Database size={24} className="mx-auto mb-2 opacity-40" />
                  暂无知识库，请先在知识库页面创建
                </div>
              ) : (
                <div className="space-y-2">
                  {allKBs.map(kb => {
                    const checked = linkedKBs.includes(kb.id)
                    return (
                      <button
                        key={kb.id}
                        type="button"
                        onClick={() => setLinkedKBs(prev =>
                          checked ? prev.filter(id => id !== kb.id) : [...prev, kb.id]
                        )}
                        className={clsx(
                          'w-full flex items-center gap-3 rounded-lg border p-3 text-left transition-colors',
                          checked
                            ? 'border-indigo-300 bg-indigo-50'
                            : 'border-gray-200 bg-white hover:border-gray-300'
                        )}
                      >
                        {checked
                          ? <CheckSquare size={15} className="text-indigo-600 shrink-0" />
                          : <Square size={15} className="text-gray-300 shrink-0" />}
                        <div className="min-w-0">
                          <p className="text-sm font-medium text-gray-800 truncate">{kb.name}</p>
                          {kb.description && (
                            <p className="text-xs text-gray-500 truncate">{kb.description}</p>
                          )}
                        </div>
                        <div className="ml-auto flex gap-1.5 shrink-0">
                          {kb.index_status?.bm25?.exists && (
                            <span className="text-xs bg-blue-100 text-blue-600 px-1.5 py-0.5 rounded">BM25</span>
                          )}
                          {(kb.index_status as any)?.pageindex?.exists && (
                            <span className="text-xs bg-orange-100 text-orange-600 px-1.5 py-0.5 rounded">PageIndex</span>
                          )}
                          {kb.index_status?.wiki?.exists && (
                            <span className="text-xs bg-green-100 text-green-600 px-1.5 py-0.5 rounded">Wiki</span>
                          )}
                        </div>
                      </button>
                    )
                  })}
                </div>
              )}
            </div>

            <Button
              onClick={() => kbMutation.mutate()}
              loading={kbMutation.isPending}
              icon={<Save size={14} />}
            >
              保存知识库绑定
            </Button>
          </div>
        )}

        <div className="mt-8 pt-6 border-t border-gray-100 flex gap-3">
          <Button onClick={() => saveMutation.mutate()} loading={saveMutation.isPending}
            disabled={!name.trim() || !provider || !modelName}
            size="lg" icon={<Save size={15} />}>
            保存并生效
          </Button>
          <Button variant="secondary" size="lg" onClick={() => navigate(-1)}>
            取消
          </Button>
        </div>
      </Card>

      {dirPickerFor === 'work' && (
        <DirPickerModal
          initial={workDir || undefined}
          onSelect={(path) => setWorkDir(path)}
          onClose={() => setDirPickerFor(null)}
        />
      )}
      {dirPickerFor === 'source' && (
        <DirPickerModal
          initial={sourceDir || undefined}
          onSelect={(path) => setSourceDir(path)}
          onClose={() => setDirPickerFor(null)}
        />
      )}
      {dirPickerFor === 'run' && (
        <DirPickerModal
          initial={runDir || undefined}
          onSelect={(path) => setRunDir(path)}
          onClose={() => setDirPickerFor(null)}
        />
      )}
    </div>
  )
}

// ── Reusable dir input with picker button ─────────────────────────

function DirField({
  label, hint, value, onChange, onBrowse, placeholder,
  color = 'amber',
}: {
  label: string
  hint: string
  value: string
  onChange: (v: string) => void
  onBrowse: () => void
  placeholder: string
  color?: 'amber' | 'blue' | 'green'
}) {
  const iconColor = color === 'amber' ? 'text-amber-500'
    : color === 'blue' ? 'text-blue-500'
    : 'text-emerald-500'
  return (
    <div>
      <label className="block text-xs font-medium text-gray-700 mb-1">{label}</label>
      <div className="flex gap-2">
        <input
          value={value}
          onChange={e => onChange(e.target.value)}
          placeholder={placeholder}
          className="flex-1 rounded-lg border border-gray-300 px-3 py-2 text-sm font-mono focus:outline-none focus:ring-2 focus:ring-indigo-500"
        />
        <button
          type="button"
          onClick={onBrowse}
          className="flex items-center gap-1.5 px-3 py-2 border border-gray-300 rounded-lg text-sm text-gray-600 hover:bg-gray-50 hover:border-indigo-400 transition-colors shrink-0"
          title="浏览文件夹"
        >
          <FolderOpen size={15} className={iconColor} />
          浏览
        </button>
      </div>
      <p className="text-xs text-gray-400 mt-1">{hint}</p>
    </div>
  )
}
