/**
 * AgentPacks.tsx — AgentPack 管理页面 (M2 Phase H).
 *
 * Features:
 *   • 列出已安装的 packs（名称、版本、领域、权限摘要）
 *   • 从本地 zip 路径安装新 pack（loopback-only POST /install）
 *   • 卸载 pack（DELETE）
 *   • 一键"从此包创建智能体"（POST /{id}/create-agent → 跳转 /agents）
 */
import { useRef, useState, useEffect } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { useNavigate } from 'react-router-dom'
import {
  Package,
  Plus,
  Trash2,
  Bot,
  FolderOpen,
  RefreshCw,
  ShieldCheck,
  Upload,
  WifiOff,
  Terminal,
} from 'lucide-react'
import toast from 'react-hot-toast'
import { agentpacksApi, type AgentPack } from '../api/agentpacks'
import { PageHeader, Spinner, EmptyState, Button, Badge, Card } from '../components/ui'
import DirPickerModal from '../components/DirPickerModal'

// ── Permission chips ─────────────────────────────────────────────

function PermChip({ label, allowed }: { label: string; allowed: boolean }) {
  return (
    <span
      className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-medium ${
        allowed ? 'bg-red-50 text-red-600' : 'bg-green-50 text-green-700'
      }`}
    >
      {label}
    </span>
  )
}

function PermissionBadges({ perms }: { perms: AgentPack['permissions'] }) {
  return (
    <div className="flex flex-wrap gap-1 mt-2">
      <PermChip label={perms.network ? '联网' : '无网络'} allowed={perms.network} />
      <PermChip label={perms.shell ? '可执行 shell' : '无 shell'} allowed={perms.shell} />
      <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-medium bg-gray-100 text-gray-600">
        写入: {perms.file_write}
      </span>
    </div>
  )
}

// ── Domain badge ─────────────────────────────────────────────────

const DOMAIN_COLORS: Record<string, 'blue' | 'purple' | 'green' | 'yellow'> = {
  research: 'purple',
  finance: 'blue',
  legal: 'yellow',
  medical: 'green',
}

function DomainBadge({ domain }: { domain: string }) {
  return (
    <Badge variant={DOMAIN_COLORS[domain] ?? 'default'}>
      {domain}
    </Badge>
  )
}

// ── Install modal ─────────────────────────────────────────────────

function InstallModal({
  onClose,
  onInstalled,
}: {
  onClose: () => void
  onInstalled: (pack: AgentPack) => void
}) {
  const [file, setFile] = useState<File | null>(null)
  const [allowShell, setAllowShell] = useState(false)
  const [showPathFallback, setShowPathFallback] = useState(false)
  const [zipPath, setZipPath] = useState('')
  const fileInputRef = useRef<HTMLInputElement>(null)

  const mut = useMutation({
    mutationFn: () => {
      if (file) return agentpacksApi.installUpload(file, allowShell)
      return agentpacksApi.install(zipPath.trim(), allowShell)
    },
    onSuccess: (res) => {
      toast.success(`已安装：${res.installed.name} v${res.installed.version}`)
      onInstalled(res.installed)
    },
    onError: (e: any) => toast.error(e.message ?? '安装失败'),
  })

  const canInstall = file !== null || zipPath.trim().length > 0

  return (
    <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-md p-6">
        <h3 className="text-base font-semibold mb-1">安装 AgentPack</h3>
        <p className="text-xs text-gray-500 mb-4">
          选择本机 .zip 文件即可安装（仅限本机访问）
        </p>

        {/* File picker — primary */}
        <div
          onClick={() => fileInputRef.current?.click()}
          className={`
            border-2 border-dashed rounded-xl px-4 py-8 text-center cursor-pointer transition-colors
            ${file
              ? 'border-indigo-400 bg-indigo-50'
              : 'border-gray-200 hover:border-indigo-300 hover:bg-gray-50'
            }
          `}
        >
          <input
            ref={fileInputRef}
            type="file"
            accept=".zip"
            className="hidden"
            onChange={(e) => {
              const f = e.target.files?.[0] ?? null
              setFile(f)
              if (f) setZipPath('')          // 选了文件就清空路径输入
            }}
          />
          {file ? (
            <div className="space-y-1">
              <div className="flex items-center justify-center gap-2 text-indigo-600">
                <Package size={20} />
                <span className="text-sm font-medium truncate max-w-[260px]">{file.name}</span>
              </div>
              <p className="text-xs text-gray-400">{(file.size / 1024).toFixed(1)} KB</p>
              <button
                onClick={(e) => { e.stopPropagation(); setFile(null); if (fileInputRef.current) fileInputRef.current.value = '' }}
                className="text-xs text-red-400 hover:text-red-600 mt-1"
              >
                重新选择
              </button>
            </div>
          ) : (
            <div className="space-y-1 text-gray-400">
              <FolderOpen size={28} className="mx-auto" />
              <p className="text-sm font-medium text-gray-600">点击选择 .zip 文件</p>
              <p className="text-xs">或将文件拖到此处</p>
            </div>
          )}
        </div>

        {/* Drag-and-drop support */}
        {/* (handled by the div above via onClick; real drag support below) */}

        {/* Advanced: path input fallback */}
        <button
          onClick={() => setShowPathFallback(v => !v)}
          className="mt-3 text-xs text-gray-400 hover:text-gray-600 underline underline-offset-2 block"
        >
          {showPathFallback ? '▲ 隐藏路径输入' : '▼ 高级：直接填写文件路径'}
        </button>

        {showPathFallback && (
          <div className="mt-2">
            <input
              value={zipPath}
              onChange={(e) => { setZipPath(e.target.value); setFile(null) }}
              placeholder="/Users/me/packs/research.reviewer-0.1.0.zip"
              className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none"
            />
          </div>
        )}

        {/* Shell permission */}
        <label className="flex items-center gap-2 cursor-pointer select-none mt-4">
          <input
            type="checkbox"
            checked={allowShell}
            onChange={(e) => setAllowShell(e.target.checked)}
            className="rounded text-indigo-600"
          />
          <span className="text-xs text-gray-600">
            允许 shell 权限（危险：仅限受信任来源）
          </span>
        </label>

        <div className="flex justify-end gap-2 mt-5">
          <button
            onClick={onClose}
            className="px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 rounded-lg"
          >
            取消
          </button>
          <button
            onClick={() => mut.mutate()}
            disabled={!canInstall || mut.isPending}
            className="px-4 py-2 text-sm bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50 flex items-center gap-2"
          >
            {mut.isPending && <RefreshCw size={14} className="animate-spin" />}
            安装
          </button>
        </div>
      </div>
    </div>
  )
}

// ── Create-agent modal ────────────────────────────────────────────

function CreateAgentModal({
  pack,
  onClose,
  onCreated,
}: {
  pack: AgentPack
  onClose: () => void
  onCreated: (agentId: string) => void
}) {
  const [name, setName] = useState(`${pack.name} (副本)`)
  const [desc, setDesc] = useState(pack.description ?? '')

  // 3-directory config
  const [sourceDir, setSourceDir]   = useState('')
  const [workDir, setWorkDir]       = useState('')
  const [runDir, setRunDir]         = useState('')
  const [dirPickerFor, setDirPickerFor] = useState<'work' | 'source' | 'run' | null>(null)

  // Advanced customisation state
  const [showAdvanced, setShowAdvanced] = useState(false)
  const [modelProvider, setModelProvider] = useState('')
  const [modelName, setModelName] = useState('')
  const [systemPrompt, setSystemPrompt] = useState('')
  const [advancedInited, setAdvancedInited] = useState(false)

  // Fetch pack detail (includes entrypoint_config) when advanced section opens
  const detailQuery = useQuery({
    queryKey: ['agentpack-detail', pack.id],
    queryFn: () => agentpacksApi.get(pack.id),
    enabled: showAdvanced,
    staleTime: 60_000,
  })

  // Pre-fill advanced fields from entrypoint_config on first load
  useEffect(() => {
    if (detailQuery.data?.entrypoint_config && !advancedInited) {
      const cfg = detailQuery.data.entrypoint_config as Record<string, any>
      const model = (cfg.model ?? {}) as Record<string, string>
      setModelProvider(model.provider ?? '')
      setModelName(model.name ?? '')
      setSystemPrompt((cfg.systemPrompt as string) ?? '')
      setAdvancedInited(true)
    }
  }, [detailQuery.data, advancedInited])

  const mut = useMutation({
    mutationFn: () => {
      const payload: Parameters<typeof agentpacksApi.createAgent>[1] = {
        name: name.trim(),
        description: desc.trim(),
      }
      if (showAdvanced && advancedInited) {
        if (modelProvider.trim() || modelName.trim()) {
          payload.model_override = {}
          if (modelProvider.trim()) payload.model_override.provider = modelProvider.trim()
          if (modelName.trim()) payload.model_override.name = modelName.trim()
        }
        // Only send system_prompt_override if user actually edited it
        if (systemPrompt !== ((detailQuery.data?.entrypoint_config as any)?.systemPrompt ?? '')) {
          payload.system_prompt_override = systemPrompt
        }
      }
      if (workDir.trim())   payload.work_dir   = workDir.trim()
      if (sourceDir.trim()) payload.source_dir = sourceDir.trim()
      if (runDir.trim())    payload.run_dir    = runDir.trim()
      return agentpacksApi.createAgent(pack.id, payload)
    },
    onSuccess: (res) => {
      toast.success(`智能体「${res.name}」已创建`)
      onCreated(res.agent_id)
    },
    onError: (e: any) => toast.error(e.message ?? '创建失败'),
  })

  return (
    <div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-lg p-6 max-h-[90vh] overflow-y-auto">
        <h3 className="text-base font-semibold mb-1">从 Pack 创建智能体</h3>
        <p className="text-xs text-gray-500 mb-4">
          基于 <strong>{pack.name}</strong> v{pack.version}
        </p>

        <div className="space-y-3">
          <div>
            <label className="block text-xs font-medium text-gray-700 mb-1">名称 *</label>
            <input
              value={name}
              onChange={(e) => setName(e.target.value)}
              className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none"
            />
          </div>
          <div>
            <label className="block text-xs font-medium text-gray-700 mb-1">描述（可选）</label>
            <textarea
              value={desc}
              onChange={(e) => setDesc(e.target.value)}
              rows={2}
              className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm resize-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none"
            />
          </div>
        </div>

        {/* ── 三目录配置 ── */}
        <div className="mt-4 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>
          {[
            { label: '① 数据来源目录', value: sourceDir, setter: setSourceDir,
              key: 'source' as const, placeholder: '/Users/me/papers',
              hint: '只读输入数据；智能体启动时提示从此读取', color: 'blue' },
            { label: '② 工作产物目录', value: workDir, setter: setWorkDir,
              key: 'work' as const, placeholder: '/Users/me/Documents/project',
              hint: 'Bash 工具初始路径；最终交付成果写这里', color: 'amber' },
            { label: '③ 运行日志目录', value: runDir, setter: setRunDir,
              key: 'run' as const, placeholder: '留空 = 自动（工作产物目录 + /workspace）',
              hint: 'run_*/traces/中间产物；留空则自动', color: 'green' },
          ].map(({ label, value, setter, key, placeholder, hint, color }) => (
            <div key={key}>
              <label className="block text-xs font-medium text-gray-700 mb-1">{label}</label>
              <div className="flex gap-2">
                <input value={value} onChange={e => setter(e.target.value)} placeholder={placeholder}
                  className="flex-1 border border-gray-300 rounded-lg px-3 py-2 text-xs font-mono
                    focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none bg-white" />
                <button type="button" onClick={() => setDirPickerFor(key)}
                  className="flex items-center gap-1 px-3 py-2 border border-gray-300 rounded-lg
                    text-xs text-gray-600 hover:bg-gray-50 hover:border-indigo-400 transition-colors shrink-0">
                  <FolderOpen size={13}
                    className={color === 'amber' ? 'text-amber-500' : color === 'blue' ? 'text-blue-500' : 'text-emerald-500'} />
                  浏览
                </button>
              </div>
              <p className="text-[10px] text-gray-400 mt-0.5">{hint}</p>
            </div>
          ))}
        </div>

        {/* Advanced customisation toggle */}
        <button
          onClick={() => setShowAdvanced(v => !v)}
          className="mt-4 text-xs text-gray-400 hover:text-gray-600 underline underline-offset-2 block"
        >
          {showAdvanced ? '▲ 收起高级配置' : '▼ 高级配置（可选：覆盖模型 / 提示词）'}
        </button>

        {showAdvanced && (
          <div className="mt-3 border border-gray-100 rounded-xl p-4 bg-gray-50 space-y-3">
            {detailQuery.isLoading ? (
              <div className="flex justify-center py-4"><Spinner size={16} /></div>
            ) : (
              <>
                <p className="text-[11px] text-gray-400 leading-relaxed">
                  留空则使用 Pack 内置配置。仅影响此次创建的智能体实例，不修改 Pack 本身。
                </p>

                {/* Model override */}
                <div className="grid grid-cols-2 gap-2">
                  <div>
                    <label className="block text-xs font-medium text-gray-700 mb-1">模型提供商</label>
                    <input
                      value={modelProvider}
                      onChange={(e) => setModelProvider(e.target.value)}
                      placeholder="claude-code"
                      className="w-full border border-gray-300 rounded-lg px-3 py-2 text-xs font-mono focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none bg-white"
                    />
                  </div>
                  <div>
                    <label className="block text-xs font-medium text-gray-700 mb-1">模型名称</label>
                    <input
                      value={modelName}
                      onChange={(e) => setModelName(e.target.value)}
                      placeholder="sonnet"
                      list={`models-${pack.id}`}
                      className="w-full border border-gray-300 rounded-lg px-3 py-2 text-xs font-mono focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none bg-white"
                    />
                    <datalist id={`models-${pack.id}`}>
                      {pack.model_recommended.map(m => (
                        <option key={m} value={m.split('/').pop() ?? m} />
                      ))}
                    </datalist>
                    {pack.model_recommended.length > 0 && (
                      <p className="text-[10px] text-gray-400 mt-1 truncate">
                        推荐：{pack.model_recommended.join(' / ')}
                      </p>
                    )}
                  </div>
                </div>

                {/* System prompt override */}
                <div>
                  <label className="block text-xs font-medium text-gray-700 mb-1">
                    系统提示词
                    <span className="text-gray-400 font-normal ml-1">（留空使用 Pack 默认）</span>
                  </label>
                  <textarea
                    value={systemPrompt}
                    onChange={(e) => setSystemPrompt(e.target.value)}
                    rows={7}
                    placeholder="留空则使用 Pack 内置系统提示词..."
                    className="w-full border border-gray-300 rounded-lg px-3 py-2 text-xs font-mono resize-y focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none bg-white"
                  />
                </div>
              </>
            )}
          </div>
        )}

        <div className="flex justify-end gap-2 mt-5">
          <button
            onClick={onClose}
            className="px-4 py-2 text-sm text-gray-600 hover:bg-gray-100 rounded-lg"
          >
            取消
          </button>
          <button
            onClick={() => mut.mutate()}
            disabled={!name.trim() || mut.isPending}
            className="px-4 py-2 text-sm bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 disabled:opacity-50 flex items-center gap-2"
          >
            {mut.isPending && <RefreshCw size={14} className="animate-spin" />}
            创建智能体
          </button>
        </div>
      </div>
      {dirPickerFor === 'work' && (
        <DirPickerModal initial={workDir || undefined}
          onSelect={setWorkDir} onClose={() => setDirPickerFor(null)} />
      )}
      {dirPickerFor === 'source' && (
        <DirPickerModal initial={sourceDir || undefined}
          onSelect={setSourceDir} onClose={() => setDirPickerFor(null)} />
      )}
      {dirPickerFor === 'run' && (
        <DirPickerModal initial={runDir || undefined}
          onSelect={setRunDir} onClose={() => setDirPickerFor(null)} />
      )}
    </div>
  )
}

// ── Pack card ────────────────────────────────────────────────────

function PackCard({
  pack,
  onUninstall,
  onCreateAgent,
  onUpdateZip,
  updating,
}: {
  pack: AgentPack
  onUninstall: () => void
  onCreateAgent: () => void
  /** 选择新版 .zip 后回调 — 更新包并把新配置同步到由它创建的智能体 */
  onUpdateZip: (file: File) => void
  updating?: boolean
}) {
  const updateInputRef = useRef<HTMLInputElement>(null)
  return (
    <Card className="flex flex-col gap-3 hover:shadow-md transition-shadow">
      {/* Header */}
      <div className="flex items-start justify-between">
        <div className="flex items-center gap-3 min-w-0">
          <div className="p-2 bg-indigo-50 rounded-lg shrink-0">
            <Package size={18} className="text-indigo-600" />
          </div>
          <div className="min-w-0">
            <p className="text-sm font-semibold text-gray-900 truncate">{pack.name}</p>
            <p className="text-xs text-gray-400">
              v{pack.version} &nbsp;·&nbsp;
              <span className="font-mono text-[10px]">{pack.id}</span>
            </p>
          </div>
        </div>
        <button
          onClick={onUninstall}
          className="text-gray-300 hover:text-red-500 transition-colors p-1 shrink-0"
          title="卸载"
        >
          <Trash2 size={14} />
        </button>
      </div>

      {/* Domain + audience */}
      <div className="flex flex-wrap gap-1.5">
        <DomainBadge domain={pack.domain} />
        {pack.audience.slice(0, 2).map((a) => (
          <Badge key={a} variant="default">
            {a}
          </Badge>
        ))}
      </div>

      {/* Description */}
      {pack.description && (
        <p className="text-xs text-gray-500 line-clamp-2">{pack.description}</p>
      )}

      {/* Permission summary */}
      <div className="text-[11px] text-gray-400 leading-relaxed border-t border-gray-100 pt-2">
        {pack.permission_summary || (
          <PermissionBadges perms={pack.permissions} />
        )}
      </div>

      {/* Actions */}
      <div className="flex gap-2 mt-auto pt-2 border-t border-gray-100">
        <Button
          onClick={onCreateAgent}
          size="sm"
          className="flex-1"
          icon={<Bot size={13} />}
        >
          创建智能体
        </Button>
        <Button
          variant="secondary"
          size="sm"
          icon={<Upload size={13} />}
          disabled={updating}
          onClick={() => updateInputRef.current?.click()}
          title="上传新版 .zip 更新此包，并让基于它创建的智能体跑最新配置"
        >
          {updating ? '更新中…' : '更新'}
        </Button>
        <input
          ref={updateInputRef}
          type="file"
          accept=".zip"
          className="hidden"
          onChange={(e) => {
            const f = e.target.files?.[0]
            if (f) onUpdateZip(f)
            e.target.value = ''  // 允许重复选择同一文件
          }}
        />
      </div>
    </Card>
  )
}

// ── Main page ────────────────────────────────────────────────────

export default function AgentPacks() {
  const navigate = useNavigate()
  const qc = useQueryClient()

  const [showInstall, setShowInstall] = useState(false)
  const [createPack, setCreatePack] = useState<AgentPack | null>(null)

  const { data, isLoading, refetch } = useQuery({
    queryKey: ['agentpacks'],
    queryFn: agentpacksApi.list,
  })

  const uninstallMut = useMutation({
    mutationFn: (packId: string) => agentpacksApi.uninstall(packId),
    onSuccess: (_, packId) => {
      toast.success('已卸载')
      qc.invalidateQueries({ queryKey: ['agentpacks'] })
    },
    onError: (e: any) => toast.error(e.message ?? '卸载失败'),
  })

  const updateMut = useMutation({
    mutationFn: ({ packId, file }: { packId: string; file: File }) =>
      agentpacksApi.updateUpload(packId, file),
    onSuccess: (res) => {
      const n = res.refreshed_agents.length
      toast.success(
        `已更新「${res.installed.name}」 v${res.previous_version} → v${res.installed.version}` +
        (n > 0 ? `，${n} 个智能体已切换到最新配置（可在版本历史回滚）` : ''),
        { duration: 6000 },
      )
      qc.invalidateQueries({ queryKey: ['agentpacks'] })
      qc.invalidateQueries({ queryKey: ['agents'] })
    },
    onError: (e: any) => toast.error(e.message ?? '更新失败'),
  })

  const packs = data?.agentpacks ?? []

  return (
    <div className="p-6 max-w-6xl mx-auto">
      <PageHeader
        title="智能体包"
        description={
          data
            ? `已安装 ${data.count} 个 AgentPack`
            : '管理可复用的智能体模版包'
        }
        action={
          <div className="flex gap-2">
            <Button
              variant="secondary"
              size="sm"
              icon={<RefreshCw size={14} />}
              onClick={() => refetch()}
            >
              刷新
            </Button>
            <Button
              size="sm"
              icon={<Upload size={14} />}
              onClick={() => setShowInstall(true)}
            >
              安装 Pack
            </Button>
          </div>
        }
      />

      {/* Security notice banner */}
      <div className="mb-6 flex items-start gap-3 bg-amber-50 border border-amber-200 rounded-lg px-4 py-3 text-xs text-amber-800">
        <ShieldCheck size={16} className="mt-0.5 shrink-0 text-amber-600" />
        <div>
          <strong>安全提示</strong>：只安装来自可信来源的 Pack。
          内置科研 Pack（research.*）本地优先运行，
          <WifiOff size={11} className="inline mx-0.5 align-middle" />无网络、
          <Terminal size={11} className="inline mx-0.5 align-middle" />无 shell。
          第三方 Pack 请仔细核查权限摘要。
        </div>
      </div>

      {isLoading && (
        <div className="flex items-center justify-center h-40">
          <Spinner />
        </div>
      )}

      {!isLoading && packs.length === 0 && (
        <EmptyState
          icon={<Package size={48} className="text-gray-300" />}
          title="还没有安装 AgentPack"
          description="AgentPack 是可复用的智能体模版，支持一键从 Pack 创建智能体。内置三个科研 Pack 可直接使用。"
          action={
            <Button
              icon={<Plus size={16} />}
              onClick={() => setShowInstall(true)}
            >
              安装 Pack
            </Button>
          }
        />
      )}

      {!isLoading && packs.length > 0 && (
        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
          {packs.map((pack) => (
            <PackCard
              key={pack.id}
              pack={pack}
              onUninstall={() => {
                if (confirm(`确认卸载「${pack.name}」？此操作不可恢复。`)) {
                  uninstallMut.mutate(pack.id)
                }
              }}
              onCreateAgent={() => setCreatePack(pack)}
              onUpdateZip={(file) => updateMut.mutate({ packId: pack.id, file })}
              updating={updateMut.isPending && updateMut.variables?.packId === pack.id}
            />
          ))}
        </div>
      )}

      {/* Modals */}
      {showInstall && (
        <InstallModal
          onClose={() => setShowInstall(false)}
          onInstalled={(pack) => {
            setShowInstall(false)
            qc.invalidateQueries({ queryKey: ['agentpacks'] })
          }}
        />
      )}

      {createPack && (
        <CreateAgentModal
          pack={createPack}
          onClose={() => setCreatePack(null)}
          onCreated={(agentId) => {
            setCreatePack(null)
            navigate('/agents')
          }}
        />
      )}
    </div>
  )
}
