'use client';

/**
 * 工具调用 / 结果的人类可读卡片
 * - ToolUseCard: 把 toolName + input 渲染成 "🔍 正在搜索：xxx"
 * - ToolResultCard: 按 toolName / output 形状派发不同 UI（TODO / Task / Cron / web_search /
 *   knowledge_query / 通用兜底）。新增工具 case 在这里加。
 */

import type { ReactNode } from 'react';
import { CheckCircle2, XCircle } from 'lucide-react';

// ---------------------------------------------------------------------------
// 工具调用 / 结果的人类可读卡片
// ---------------------------------------------------------------------------

/** 把 toolName + input 渲染成自然语言："🔍 正在搜索：xxx" */
function describeToolUse(toolName: string | undefined, input: Record<string, unknown> | undefined): { icon: string; label: string } {
  const i = input ?? {};
  const s = (k: string): string => String(i[k] ?? '').trim();
  switch (toolName) {
    case 'web_search':
      return { icon: '🔍', label: `正在搜索：${s('query') || '...'}` };
    case 'web_fetch':
      return { icon: '🌐', label: `抓取页面：${s('url') || '...'}` };
    case 'TodoWrite':
      return { icon: '📝', label: `更新 TODO 清单` };
    case 'TaskCreate':
      return { icon: '🧩', label: `创建任务：${s('title') || '...'}` };
    case 'TaskUpdate':
      return { icon: '🧩', label: `更新任务：${s('taskId').slice(0, 8) || '...'}` };
    case 'TaskList':
      return { icon: '🧩', label: `列出任务` };
    case 'TaskStop':
      return { icon: '🛑', label: `取消任务：${s('taskId').slice(0, 8) || '...'}` };
    case 'CronCreate':
      return { icon: '⏰', label: `创建定时：${s('name') || '...'} (${s('cronExpr') || '?'})` };
    case 'CronList':
      return { icon: '⏰', label: `列出定时任务` };
    case 'CronUpdate':
      return { icon: '⏰', label: `更新定时：${s('cronId').slice(0, 8) || '...'}` };
    case 'CronDelete':
      return { icon: '🛑', label: `删除定时：${s('cronId').slice(0, 8) || '...'}` };
    case 'knowledge_query':
      return { icon: '📚', label: `查公司知识库：${s('question') || '...'}` };
    case 'project_query':
      return { icon: '📁', label: `查项目：${s('query') || '...'}` };
    case 'approval_submit':
      return { icon: '📝', label: `提交审批：${s('title') || s('businessType') || '...'}` };
    case 'file_save':
      return { icon: '💾', label: `保存文件：${s('name') || s('path') || '...'}` };
    case 'scratchpad_read':
      return { icon: '📋', label: `读暂存板：${s('key') || ''}` };
    case 'scratchpad_write':
      return { icon: '📋', label: `写暂存板：${s('key') || ''}` };
    case 'delegate_task':
      return { icon: '🧠', label: `派 sub-agent：${s('title') || s('task') || '...'}` };
    case 'SendMessage':
      return { icon: '✉️', label: `给 sub-agent 发消息：${s('prompt').slice(0, 30) || ''}` };
    case 'ask_user':
      return { icon: '❓', label: `反问用户` };
    case 'Shell.openExternal':
      return { icon: '🌐', label: `打开链接：${s('url') || '...'}` };
    case 'File.read':
      return { icon: '📖', label: `读文件：${s('path') || '...'}` };
    case 'File.write':
      return { icon: '✏️', label: `写文件：${s('path') || '...'}` };
    case 'File.list':
      return { icon: '📂', label: `列目录：${s('path') || '/'}` };
    case 'Shell.exec':
      return { icon: '⌨️', label: `执行命令：${s('cmd') || '...'}` };
    case 'Clipboard.read':
      return { icon: '📋', label: `读剪贴板` };
    case 'Clipboard.write':
      return { icon: '📋', label: `写剪贴板` };
    case 'Notify.push':
      return { icon: '🔔', label: `通知：${s('title') || ''}` };
    default:
      return { icon: '🛠️', label: toolName ?? 'tool' };
  }
}

export function ToolUseCard({ toolName, input }: { toolName?: string; input?: Record<string, unknown> }) {
  const { icon, label } = describeToolUse(toolName, input);
  return (
    <div className="flex" data-testid="agent-msg-tool_use">
      <div className="inline-flex items-center gap-2 rounded-full bg-stone-100 px-3 py-1.5 text-xs text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400">
        <span className="text-sm leading-none">{icon}</span>
        <span className="truncate" title={label}>
          {label}
        </span>
      </div>
    </div>
  );
}

interface ToolResultCardProps {
  toolName?: string;
  ok: boolean;
  output: unknown;
  errorMessage?: string;
}

export function ToolResultCard({ toolName, ok, output, errorMessage }: ToolResultCardProps) {
  // 错误：用户友好提示，不暴露 stack-trace 细节
  if (!ok) {
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="inline-flex items-center gap-2 rounded-full bg-red-50 px-3 py-1.5 text-xs text-red-700 dark:bg-red-950/30 dark:text-red-300">
          <XCircle className="h-3 w-3" aria-hidden />
          <span>工具暂不可用</span>
          <DetailsToggle title="错误详情">
            <pre className="whitespace-pre-wrap break-words text-[10px]">
              {errorMessage ?? 'unknown error'}
            </pre>
          </DetailsToggle>
        </div>
      </div>
    );
  }

  const out = (output ?? {}) as Record<string, unknown>;

  // TodoWrite output: { todos: [{id, text, completed}], total, completed, pending }
  if (Array.isArray(out.todos) && out.todos.length > 0 && typeof (out.todos[0] as Record<string, unknown>).completed === 'boolean') {
    const todos = out.todos as Array<{ id: string; text: string; completed: boolean }>;
    const done = Number(out.completed ?? todos.filter((t) => t.completed).length);
    const total = Number(out.total ?? todos.length);
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="w-full max-w-2xl rounded-lg border border-stone-200 bg-white p-3 dark:border-neutral-800 dark:bg-neutral-900">
          <div className="mb-2 flex items-center gap-2 text-[11px] font-medium text-neutral-500 dark:text-neutral-400">
            <span>📝 TODO</span>
            <span className="text-neutral-400">{done} / {total} 完成</span>
            <div className="ml-auto h-1 w-24 overflow-hidden rounded-full bg-stone-200 dark:bg-neutral-800">
              <div
                className="h-full bg-emerald-500 transition-all"
                style={{ width: total === 0 ? '0%' : `${Math.round((done / total) * 100)}%` }}
              />
            </div>
          </div>
          <ul className="space-y-1">
            {todos.map((t) => (
              <li key={t.id} className="flex items-start gap-2 text-sm leading-6">
                <span
                  className={`mt-0.5 inline-flex h-4 w-4 shrink-0 items-center justify-center rounded border ${
                    t.completed
                      ? 'border-emerald-500 bg-emerald-500 text-white'
                      : 'border-stone-300 dark:border-neutral-600'
                  }`}
                  aria-hidden
                >
                  {t.completed ? <span className="text-[10px]">✓</span> : null}
                </span>
                <span
                  className={`flex-1 ${
                    t.completed
                      ? 'text-neutral-400 line-through dark:text-neutral-500'
                      : 'text-neutral-800 dark:text-neutral-200'
                  }`}
                >
                  {t.text}
                </span>
              </li>
            ))}
          </ul>
        </div>
      </div>
    );
  }

  // Task* output: { tasks: [{id, title, status, progress, ...}] } 或单个 { task: {...} }
  const taskList = Array.isArray(out.tasks)
    ? (out.tasks as Array<Record<string, unknown>>)
    : out.task && typeof out.task === 'object'
      ? [out.task as Record<string, unknown>]
      : null;
  if (taskList && taskList.length > 0 && typeof taskList[0].title === 'string' && typeof taskList[0].status === 'string') {
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="w-full max-w-2xl space-y-1.5">
          <div className="text-[11px] font-medium text-neutral-500 dark:text-neutral-400">
            🧩 任务 · {taskList.length} 条
          </div>
          {taskList.map((task) => {
            const status = String(task.status);
            const progress = Number(task.progress ?? 0);
            const statusColor = {
              PENDING: 'bg-stone-200 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400',
              IN_PROGRESS: 'bg-blue-100 text-blue-700 dark:bg-blue-950/40 dark:text-blue-300',
              COMPLETED: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300',
              CANCELLED: 'bg-stone-100 text-neutral-500 dark:bg-neutral-900 dark:text-neutral-500',
              FAILED: 'bg-red-100 text-red-700 dark:bg-red-950/40 dark:text-red-300',
            }[status] ?? 'bg-stone-100';
            return (
              <div
                key={String(task.id)}
                className="rounded-lg border border-stone-200 bg-white p-2.5 dark:border-neutral-800 dark:bg-neutral-900"
              >
                <div className="flex items-center gap-2">
                  <span className={`rounded px-1.5 py-0.5 text-[10px] font-medium uppercase ${statusColor}`}>
                    {status}
                  </span>
                  <span className="flex-1 text-sm font-medium text-neutral-900 dark:text-neutral-100">
                    {String(task.title)}
                  </span>
                  {progress > 0 ? (
                    <span className="text-[11px] text-neutral-400">{progress}%</span>
                  ) : null}
                </div>
                {task.description ? (
                  <p className="mt-1 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400">
                    {String(task.description)}
                  </p>
                ) : null}
                {progress > 0 ? (
                  <div className="mt-1.5 h-1 overflow-hidden rounded-full bg-stone-100 dark:bg-neutral-800">
                    <div
                      className="h-full bg-blue-500 transition-all"
                      style={{ width: `${Math.min(100, Math.max(0, progress))}%` }}
                    />
                  </div>
                ) : null}
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // Cron* output: { crons: [{id, name, cronExpr, enabled, nextRunAt, ...}] } 或 { cron: {...} }
  const cronList = Array.isArray(out.crons)
    ? (out.crons as Array<Record<string, unknown>>)
    : out.cron && typeof out.cron === 'object'
      ? [out.cron as Record<string, unknown>]
      : null;
  if (cronList && cronList.length > 0 && typeof cronList[0].cronExpr === 'string') {
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="w-full max-w-2xl space-y-1.5">
          <div className="text-[11px] font-medium text-neutral-500 dark:text-neutral-400">
            ⏰ 定时任务 · {cronList.length} 条
          </div>
          {cronList.map((c) => {
            const enabled = Boolean(c.enabled);
            const next = c.nextRunAt ? new Date(String(c.nextRunAt)) : null;
            const last = c.lastRunAt ? new Date(String(c.lastRunAt)) : null;
            const runCount = Number(c.runCount ?? 0);
            const failCount = Number(c.failCount ?? 0);
            return (
              <div
                key={String(c.id)}
                className={`rounded-lg border p-2.5 ${
                  enabled
                    ? 'border-stone-200 bg-white dark:border-neutral-800 dark:bg-neutral-900'
                    : 'border-stone-200 bg-stone-50 dark:border-neutral-800 dark:bg-neutral-900/50'
                }`}
              >
                <div className="flex items-center gap-2">
                  <span
                    className={`rounded px-1.5 py-0.5 text-[10px] font-medium uppercase ${
                      enabled
                        ? 'bg-emerald-100 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300'
                        : 'bg-stone-200 text-neutral-500 dark:bg-neutral-800 dark:text-neutral-500'
                    }`}
                  >
                    {enabled ? 'ENABLED' : 'PAUSED'}
                  </span>
                  <span className="flex-1 text-sm font-medium text-neutral-900 dark:text-neutral-100">
                    {String(c.name)}
                  </span>
                  <code className="rounded bg-stone-100 px-1.5 py-0.5 font-mono text-[10px] text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400">
                    {String(c.cronExpr)}
                  </code>
                </div>
                <div className="mt-1.5 grid grid-cols-2 gap-2 text-[11px] text-neutral-500 dark:text-neutral-400">
                  <div>
                    下次：<span className="text-neutral-700 dark:text-neutral-300">{next ? next.toLocaleString() : '—'}</span>
                  </div>
                  <div>
                    上次：<span className="text-neutral-700 dark:text-neutral-300">{last ? last.toLocaleString() : '从未'}</span>
                  </div>
                  <div>累计 {runCount} 次{failCount > 0 ? ` · 失败 ${failCount}` : ''}</div>
                </div>
                {c.prompt ? (
                  <p className="mt-1 line-clamp-2 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400">
                    💬 {String(c.prompt)}
                  </p>
                ) : null}
                {c.lastError ? (
                  <p className="mt-1 line-clamp-2 text-[10px] text-red-600 dark:text-red-400">
                    ⚠ {String(c.lastError)}
                  </p>
                ) : null}
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // web_search 0 结果：友好提示，不走通用兜底
  if (Array.isArray(out.results) && out.results.length === 0 && typeof out.query === 'string') {
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="inline-flex items-center gap-2 rounded-full bg-stone-100 px-3 py-1.5 text-xs text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400">
          <span>🔍 未找到「{String(out.query)}」相关结果</span>
        </div>
      </div>
    );
  }

  // web_search：output.results = [{ url, title, snippet }]
  if (Array.isArray(out.results) && out.results.length > 0 && (out.results[0] as Record<string, unknown>).url) {
    const results = out.results as Array<{ url: string; title: string; snippet: string }>;
    const provider = String(out.provider ?? '');
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="w-full max-w-2xl space-y-2">
          <div className="text-[11px] text-neutral-400 dark:text-neutral-500">
            {results.length} 条结果{provider ? ` · 来自 ${provider}` : ''}
          </div>
          {results.slice(0, 5).map((r, i) => (
            <a
              key={i}
              href={r.url}
              target="_blank"
              rel="noopener noreferrer"
              className="block rounded-lg border border-stone-200 bg-white px-3 py-2 transition hover:border-neutral-400 hover:shadow-sm dark:border-neutral-800 dark:bg-neutral-900 dark:hover:border-neutral-600"
            >
              <div className="text-xs text-neutral-400 dark:text-neutral-500">{shortDomain(r.url)}</div>
              <div className="mt-0.5 line-clamp-1 text-sm font-medium text-blue-700 hover:underline dark:text-blue-400">
                {r.title}
              </div>
              {r.snippet ? (
                <p className="mt-1 line-clamp-2 text-xs leading-5 text-neutral-600 dark:text-neutral-400">
                  {r.snippet}
                </p>
              ) : null}
            </a>
          ))}
        </div>
      </div>
    );
  }

  // knowledge_query：output.answer + output.sources
  if (typeof out.answer === 'string') {
    const sources = Array.isArray(out.sources) ? (out.sources as Array<Record<string, unknown>>) : [];
    return (
      <div className="flex" data-testid="agent-msg-tool_result">
        <div className="w-full max-w-2xl rounded-lg border border-stone-200 bg-white p-3 dark:border-neutral-800 dark:bg-neutral-900">
          <div className="mb-1 text-[11px] font-medium text-neutral-400 dark:text-neutral-500">📚 知识库回答</div>
          <div className="text-sm leading-6 text-neutral-700 dark:text-neutral-300">{String(out.answer)}</div>
          {sources.length > 0 ? (
            <div className="mt-2 space-y-0.5 text-[11px] text-neutral-500">
              <div className="font-medium">引用：</div>
              {sources.slice(0, 5).map((s, i) => {
                const title = String(s.title ?? s.name ?? `源 ${i + 1}`);
                const url = s.url || s.link;
                return url ? (
                  <a key={i} href={String(url)} target="_blank" rel="noopener noreferrer" className="block truncate text-blue-600 hover:underline">
                    · {title}
                  </a>
                ) : (
                  <div key={i} className="truncate">· {title}</div>
                );
              })}
            </div>
          ) : null}
        </div>
      </div>
    );
  }

  // 通用兜底：成功结果，折叠 JSON 详情
  return (
    <div className="flex" data-testid="agent-msg-tool_result">
      <div className="inline-flex items-center gap-2 rounded-full bg-emerald-50 px-3 py-1.5 text-xs text-emerald-700 dark:bg-emerald-950/30 dark:text-emerald-300">
        <CheckCircle2 className="h-3 w-3" aria-hidden />
        <span>{describeToolResultBrief(toolName, out)}</span>
        <DetailsToggle title="原始结果">
          <pre className="max-h-60 overflow-auto whitespace-pre-wrap break-words text-[10px]">
            {JSON.stringify(out, null, 2)}
          </pre>
        </DetailsToggle>
      </div>
    </div>
  );
}

function describeToolResultBrief(toolName: string | undefined, out: Record<string, unknown>): string {
  // 简短描述：项目查到 N 条 / 审批已提交 / 文件已保存 / ...
  if (Array.isArray(out.items)) return `${toolName ?? '工具'} 返回 ${out.items.length} 条`;
  if (typeof out.processInstanceId === 'string') return `审批已提交`;
  if (typeof out.path === 'string' && typeof out.bytesWritten === 'number') return `已保存 (${out.bytesWritten} bytes)`;
  return `${toolName ?? '工具'} 完成`;
}

function shortDomain(url: string): string {
  try {
    const u = new URL(url);
    return u.hostname.replace(/^www\./, '');
  } catch {
    return url.slice(0, 40);
  }
}

function DetailsToggle({ title, children }: { title: string; children: ReactNode }) {
  return (
    <details className="ml-1">
      <summary className="cursor-pointer text-[10px] text-neutral-400 hover:text-neutral-600 dark:hover:text-neutral-300">
        {title}
      </summary>
      <div className="mt-1 rounded bg-stone-50 p-2 dark:bg-neutral-950/40">{children}</div>
    </details>
  );
}
