import { fireEvent, render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { Inspector } from "@/components/inspector/Inspector";
import { finalResultItem, storyItem } from "@/lib/layout";
import { makeStory, makeView } from "@/tests/fixtures";

describe("Inspector information layers", () => {
  it("keeps the readable Inspector as the default business surface and opens lineage separately", () => {
    const item = storyItem(makeStory("objective", "objective", "decision", { title: "创作目标", detailRef: "run:objective" }));
    const onModeChange = vi.fn();
    render(<Inspector
      item={item}
      mode="business"
      onModeChange={onModeChange}
      onClose={vi.fn()}
      detail={{
        detailKind: "agent-decision",
        question: "这次构建要形成什么创作方向？",
        blocks: [{ type: "summary", title: "当前保存的创作方向", value: "把毛驴效应讲清楚，并给出可执行建议。" }],
        technical: { source: "database" },
      }}
    />);

    expect(screen.getByText("这次构建要形成什么创作方向？")).toBeInTheDocument();
    expect(screen.getByText("把毛驴效应讲清楚，并给出可执行建议。")).toBeInTheDocument();
    expect(screen.queryByText("数据依据")).not.toBeInTheDocument();
    fireEvent.click(screen.getByRole("button", { name: "打开数据来源" }));
    expect(onModeChange).toHaveBeenCalledWith("lineage");
  });

  it("renders planning analysis as a real pre-build activity with complete prose", () => {
    const item = storyItem(makeStory("run:planning-analysis", "planning-analysis", "execution", {
      title: "创作规划解析",
      detailRef: "event:3760",
    }));
    const fullThought = "账号结构模式与领域准确性下限已经完成分析。".repeat(20);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      businessSections: [
        { id: "summary", title: "规划概要", content: "首轮竞争不同的段落骨架。", variant: "summary", visualRole: "key-result" },
        { id: "thought", title: "完整思考", content: fullThought, variant: "report", visualRole: "section" },
        { id: "plan", title: "执行计划", content: "保存创作目标，然后开启首轮。", visualRole: "section" },
        { id: "action", title: "下一步", content: "写入创作总目标", visualRole: "reason" },
      ],
      technical: { event: { id: 3760, event_name: "think_and_plan" } },
    }} />);

    expect(screen.getByText("构建开始前的规划")).toBeInTheDocument();
    expect(screen.getByText("创作规划解析")).toBeInTheDocument();
    expect(screen.getByText(fullThought)).toBeInTheDocument();
    expect(screen.getByText("写入创作总目标")).toBeInTheDocument();
  });

  it("losslessly breaks a consecutively numbered execution plan into readable lines", () => {
    const item = storyItem(makeStory("run:planning-analysis", "planning-analysis", "execution", {
      title: "创作规划解析",
      detailRef: "event:4565",
    }));
    const plan = "1)save_script_direction 2)begin_round首轮：立段落结构 3)后续轮次填充元素、金句、行动指南";
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      businessSections: [
        { id: "plan", title: "执行计划", content: plan, visualRole: "section" },
      ],
      technical: {},
    }} />);

    const rendered = container.querySelector(".inspectorPanel .richText");
    expect(rendered).toHaveTextContent("1)save_script_direction 2)begin_round首轮：立段落结构 3)后续轮次填充元素、金句、行动指南");
    expect(rendered?.querySelectorAll("br")).toHaveLength(2);
  });

  it("keeps an unnumbered execution plan unchanged", () => {
    const item = storyItem(makeStory("run:planning-analysis", "planning-analysis", "execution"));
    const plan = "准备阶段：写入总目标后进入轮次循环，首轮先立段落结构。";
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      businessSections: [{ id: "plan", title: "执行计划", content: plan }],
      technical: {},
    }} />);

    expect(screen.getByText(plan)).toBeInTheDocument();
    expect(container.querySelector(".inspectorPanel .richText br")).toBeNull();
  });

  it("renders optional implementation-task sections with semantic hierarchy", () => {
    const item = storyItem(makeStory("round:2:branch:3:task", "branch-task", "execution", {
      title: "实现任务",
    }), 2, 3);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      businessSections: [
        { id: "task-scope-1", title: "实现范围", content: "五段骨架", visualRole: "section" },
        { id: "task-goal-2", title: "目标", content: "补齐每段文字。", variant: "summary", visualRole: "key-result" },
        { id: "task-materials-3", title: "必用素材（已核实）", content: "- 领域事实 A", variant: "report", visualRole: "evidence", presentation: "document" },
        { id: "task-avoid-4", title: "需要避免", content: "不得改动原文。", variant: "report", visualRole: "notice", presentation: "document" },
      ],
      technical: {},
    }} />);

    expect(screen.getByRole("heading", { name: "实现范围" }).closest("section")).toHaveAttribute("data-visual-role", "section");
    expect(screen.getByRole("heading", { name: "目标" }).closest("section")).toHaveAttribute("data-visual-role", "key-result");
    expect(screen.getByRole("heading", { name: "必用素材（已核实）" }).closest("section")).toHaveAttribute("data-visual-role", "evidence");
    expect(screen.getByRole("heading", { name: "需要避免" }).closest("section")).toHaveAttribute("data-visual-role", "notice");
    expect(screen.queryAllByRole("heading", { name: "实现任务" })).toHaveLength(1);
  });

  it("keeps business prose separate from technical records", () => {
    const item = storyItem(makeStory("evaluation", "multipath-review"), 1);
    render(<Inspector
      item={item}
      tab="business"
      onTab={vi.fn()}
      onClose={vi.fn()}
      detail={{
        businessSections: [
          { id: "conclusion", title: "评审结论", content: "部分通过", variant: "summary" },
          { id: "report", title: "评审说明", content: "- 结构清晰\n- 仍需补足正文", variant: "report" },
        ],
        technical: { event_name: "script_multipath_evaluator", input_preview: "raw-json" },
      }}
    />);

    expect(screen.getByText("部分通过")).toBeInTheDocument();
    expect(screen.getByText("结构清晰")).toBeInTheDocument();
    expect(screen.queryByText(/script_multipath_evaluator/)).not.toBeInTheDocument();
    expect(screen.queryByText("运行记录关联")).not.toBeInTheDocument();
  });

  it("shows raw fields only after opening technical records", () => {
    const onTab = vi.fn();
    const item = storyItem(makeStory("evaluation", "multipath-review"), 1);
    const detail = {
      businessSections: [{ id: "conclusion", title: "评审结论", content: "通过", variant: "summary" as const }],
      technical: { event_name: "script_multipath_evaluator" },
    };
    const { rerender } = render(<Inspector item={item} tab="business" onTab={onTab} onClose={vi.fn()} detail={detail} />);
    fireEvent.click(screen.getByRole("tab", { name: "技术详情" }));
    expect(onTab).toHaveBeenCalledWith("technical");

    rerender(<Inspector item={item} tab="technical" onTab={onTab} onClose={vi.fn()} detail={detail} />);
    expect(screen.getByText("原始记录")).toBeInTheDocument();
    expect(screen.getByText(/script_multipath_evaluator/)).toBeInTheDocument();
  });

  it("prefers structured business items over a large markdown fallback", () => {
    const item = storyItem(makeStory("objective", "objective"), 1);
    render(<Inspector
      item={item}
      tab="business"
      onTab={vi.fn()}
      onClose={vi.fn()}
      detail={{
        businessSections: [{
          id: "inputs",
          title: "决策前读取",
          content: "这段巨型 Markdown 不应在存在结构化列表时展示",
          items: [
            { label: "选题", value: "米豆腐炒肉", detailRef: "event:2146" },
            { label: "账号段落模式", value: "成品展示 → 食材与热量 → 教学步骤", sourceNotice: "record-missing" },
          ],
        }],
        technical: { event_ids: [2146] },
      }}
    />);

    expect(screen.getByText("选题")).toBeInTheDocument();
    expect(screen.getByText("米豆腐炒肉")).toBeInTheDocument();
    expect(screen.getByText("账号段落模式")).toBeInTheDocument();
    expect(screen.getByText("记录缺失")).toBeInTheDocument();
    expect(screen.queryByText(/巨型 Markdown/)).not.toBeInTheDocument();
    expect(screen.queryByText("event:2146")).not.toBeInTheDocument();
  });

  it("keeps the full build summary when final artifact details load", () => {
    const view = makeView();
    view.finalResult.summary = "构建总结全文：脚本已经完成结构与表达检查。";
    render(<Inspector
      item={finalResultItem(view)}
      tab="business"
      onTab={vi.fn()}
      onClose={vi.fn()}
      detail={{
        businessSections: [
          { id: "build-summary", title: "构建总结", content: "构建总结全文：脚本已经完成结构与表达检查。" },
          { id: "summary", title: "主脚本规模", content: "3 个段落、5 个元素、4 条关联" },
        ],
        changes: { summary: "当前主脚本内容", sections: [], exactness: "current-only" },
        technical: { source: "database" },
      }}
    />);

    expect(screen.getByText("构建总结全文：脚本已经完成结构与表达检查。")).toBeInTheDocument();
    expect(screen.getByText("3 个段落、5 个元素、4 条关联")).toBeInTheDocument();
  });

  it("renders V8 decision blocks without leaking technical fields into business detail", () => {
    const story = makeStory("evaluation", "round-evaluation");
    const item = storyItem(story, 1);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "evaluation",
      actor: { role: "overall-evaluator", label: "整体评审 Agent" },
      authority: "recommendation",
      question: "当前主脚本是否达到目标？",
      blocks: [
        { type: "summary", title: "总结论", value: "部分通过" },
        { type: "items", title: "问题", items: ["结尾仍需补充行动建议"] },
      ],
      technical: { source: { table: "script_build_event", eventId: 41 } },
    }} />);
    expect(screen.getByText("部分通过")).toBeInTheDocument();
    expect(screen.getByText("结尾仍需补充行动建议")).toBeInTheDocument();
    expect(screen.queryByText(/script_build_event|eventId/)).not.toBeInTheDocument();
  });

  it("keeps arrows and sentence punctuation in the original prose", () => {
    const item = storyItem(makeStory("objective", "objective"), 1);
    const prose = "概念引入→拆解分析→归纳提炼→行动指南。第二句仍属于同一段。";
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "direction",
      blocks: [{ type: "summary", title: "明确理由", value: prose }],
      technical: {},
    }} />);

    expect(screen.getByText(prose)).toBeInTheDocument();
    expect(container.querySelector(".decisionFlowList")).toBeNull();
    expect(container.querySelectorAll(".decisionReadableText p")).toHaveLength(1);
  });

  it("only inserts line breaks and indentation around an existing numbered sequence", () => {
    const item = storyItem(makeStory("objective", "objective"), 1);
    const prose = "根据原有信息形成五个部分。 1. 原文第一项； 2. 原文第二项； 3. 原文第三项。";
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "direction",
      blocks: [{ type: "summary", title: "明确理由", value: prose }],
      technical: {},
    }} />);

    expect(screen.getByText("根据原有信息形成五个部分。")).toBeInTheDocument();
    expect(screen.getByText("原文第一项；")).toBeInTheDocument();
    expect(screen.getByText("原文第二项；")).toBeInTheDocument();
    expect(screen.getByText("原文第三项。")).toBeInTheDocument();
    expect(container.querySelectorAll(".decisionReadableText ol > li")).toHaveLength(3);
  });

  it("groups creative steps and multipath evaluation content by its real semantic owner", () => {
    const item = storyItem(makeStory("creative", "candidate-output"), 1, 2);
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "creative",
      blocks: [
        {
          type: "creative-process",
          title: "创作处理",
          steps: [{ stepIndex: 4, action: "新增脚本段落", summary: "起草四元组并开始创建段落骨架。", plan: "1. 创建段落 1：封面导引\n2. 创建段落 2：概念定义", reasoning: "输入依据：账号标准科普模式。" }],
        },
        {
          type: "evaluation-branches",
          title: "逐方案评审",
          branches: [
            { subject: "方案 1", conclusion: "部分通过", achievements: ["领域信息库新增 5 条事实（id 54-58）。"], problems: ["元素创建尚未完整落地。"], evidence: "来源可指位。" },
            { subject: "方案 2", conclusion: "部分通过", achievements: ["已搭建五段骨架。"], problems: ["数量红线违规。"] },
          ],
        },
        {
          type: "evaluation-matrix",
          title: "评审标准与方案对比",
          rows: [{ criterion: "结构完备性", candidates: [{ subject: "方案 1", value: "不适用" }, { subject: "方案 2", value: "部分通过" }], basis: "仅方案二涉及" }],
        },
      ],
      technical: {},
    }} />);

    expect(screen.queryByText("6 个真实执行步骤")).not.toBeInTheDocument();
    expect(screen.getByText("1 个真实执行步骤")).toBeInTheDocument();
    expect(screen.getByText("新增脚本段落")).toBeInTheDocument();
    expect(screen.getByText("创建段落 1：封面导引")).toBeInTheDocument();
    expect(screen.getByText("领域信息库新增 5 条事实（id 54-58）。")).toBeInTheDocument();
    expect(screen.getByText("数量红线违规。")).toBeInTheDocument();
    expect(screen.getByRole("rowheader", { name: "结构完备性" })).toBeInTheDocument();
    expect(screen.getByRole("cell", { name: "仅方案二涉及" })).toBeInTheDocument();
    expect(container.querySelectorAll(".evaluationBranchList > article")).toHaveLength(2);
  });

  it("renders the complete saved script direction as its original hierarchy", () => {
    const item = storyItem(makeStory("objective", "objective"), 1);
    const sourceDocument = `## 选题价值主张
用经典心理学效应帮助读者理解决策瘫痪，并给出**"先行动再调整"**。

## 创作总目标
### 目标 1
- 目标语句：把毛驴效应科普清楚。
- 评估维度：
  - name：科普清晰度
  - 通过标准：普通读者能准确理解定义与来源。`;
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "direction",
      blocks: [
        { type: "summary", title: "当前保存的创作方向", value: sourceDocument, visualRole: "key-result", presentation: "document" },
      ],
      technical: {},
    }} />);

    expect(screen.getByRole("heading", { name: "选题价值主张" })).toBeInTheDocument();
    expect(screen.getByRole("heading", { name: "创作总目标" })).toBeInTheDocument();
    expect(screen.getByRole("heading", { name: "目标 1" })).toBeInTheDocument();
    expect(screen.getByText("通过标准：普通读者能准确理解定义与来源。")).toBeInTheDocument();
    expect(screen.getByText("先行动再调整").tagName).toBe("STRONG");
    expect(screen.queryByText(/\*\*"先行动再调整"\*\*/)).not.toBeInTheDocument();
    expect(container.querySelector('[data-presentation="document"]')).toBeInTheDocument();
  });

  it("renders the complete round goal without inferred sentence roles", () => {
    const item = storyItem(makeStory("goal", "goal"), 1);
    const completeGoal = "立起脚本的段落骨架。竞争不同的框架切分策略。本轮只做段落结构，不填充文案。";
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "direction",
      blocks: [{
        type: "summary",
        title: "本轮目标构成",
        visualRole: "key-result",
        presentation: "document",
        value: completeGoal,
      }],
      technical: {},
    }} />);

    expect(screen.getByText(completeGoal)).toBeInTheDocument();
    expect(screen.queryByText("核心目标")).not.toBeInTheDocument();
    expect(screen.queryByText("实现策略")).not.toBeInTheDocument();
    expect(screen.queryByText("范围边界")).not.toBeInTheDocument();
  });

  it("renders implementation plans as structured routes with collapsible evidence", () => {
    const item = storyItem(makeStory("plan", "plan"), 4);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "direction",
      actor: { role: "main", label: "主 Agent" },
      authority: "final",
      question: "本轮应如何组织实现方案？",
      blocks: [
        {
          type: "implementation-plan",
          title: "本轮实施路线",
          visualRole: "section",
          presentation: "plan",
          mode: "单路",
          reasoning: "这是收敛阶段的定点修复，不需要竞争。",
          routes: [{ pathIndex: 1, pathType: "内容", action: "改", target: "段落 2207、2208 的形式层", method: "产生元素", emphasis: "结构完整性" }],
        },
        { type: "items", title: "根据以下信息做出的决策", visualRole: "evidence", presentation: "list", collapsible: false, items: [{ label: "本轮目标", value: "完整目标内容", note: "持续约束；本轮必须遵守" }] },
      ],
      technical: {},
    }} />);

    expect(screen.getByText("本轮实施路线")).toBeInTheDocument();
    expect(screen.getByText("路线 1")).toBeInTheDocument();
    expect(screen.getByText("段落 2207、2208 的形式层")).toBeInTheDocument();
    expect(screen.getByText("产生元素")).toBeInTheDocument();
    expect(screen.getByText("结构完整性")).toBeInTheDocument();
    expect(screen.getByText("为什么这样规划")).toBeInTheDocument();
    expect(screen.getByText("根据以下信息做出的决策")).toBeInTheDocument();
    expect(screen.getByText("完整目标内容")).toBeVisible();
  });

  it("uses semantic roles instead of Chinese titles for hierarchy and disclosure", () => {
    const item = storyItem(makeStory("tradeoff", "data-decision"), 1);
    const { container } = render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "tradeoff",
      blocks: [
        { type: "items", title: "参考资料", visualRole: "evidence", collapsible: true, items: ["完整依据"] },
        { type: "summary", title: "执行结论", visualRole: "key-result", value: "采用方案 A" },
      ],
      technical: {},
    }} />);

    expect(screen.getByText("完整依据")).not.toBeVisible();
    expect(container.querySelector('[data-visual-role="key-result"]')).toHaveClass("is-role-key-result");
    fireEvent.click(screen.getByText("参考资料"));
    expect(screen.getByText("完整依据")).toBeVisible();
  });

  it("opens the task and rules from inside a decision Inspector", () => {
    const onPrompt = vi.fn();
    const item = storyItem(makeStory("creative", "candidate-output"), 1, 2);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} onPrompt={onPrompt} detail={{
      detailKind: "agent-decision",
      decisionType: "creative",
      actor: { role: "implementer", label: "实现 Agent" },
      authority: "implementation-scope",
      question: "当前实现方案如何形成候选产出？",
      promptRef: "prompt:event:2977",
      blocks: [],
      technical: {},
    }} />);

    fireEvent.click(screen.getByRole("button", { name: "查看实现任务与提示词" }));
    expect(onPrompt).toHaveBeenCalledWith("prompt:event:2977");
  });

  it("does not invent a recommendation-handling column without an explicit record", () => {
    const item = storyItem(makeStory("tradeoff", "multipath-decision"), 1);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "tradeoff",
      blocks: [{
        type: "comparison",
        title: "评审建议与最终决定",
        rows: [{ candidate: "方案 1", recommendation: "建议采用", finalDecision: "已采用" }],
      }],
      technical: {},
    }} />);
    expect(screen.getByText("评审建议")).toBeInTheDocument();
    expect(screen.getByText("最终决定")).toBeInTheDocument();
    expect(screen.queryByText("对建议的处理")).not.toBeInTheDocument();
    expect(screen.queryByText("没有明确记录")).not.toBeInTheDocument();
  });

  it("renders structured evaluator issues once and keeps nested outcomes readable", () => {
    const item = storyItem(makeStory("evaluation", "round-evaluation"), 1);
    render(<Inspector item={item} tab="business" onTab={vi.fn()} onClose={vi.fn()} detail={{
      detailKind: "agent-decision",
      decisionType: "evaluation",
      blocks: [{
        type: "items",
        title: "逐项结论",
        items: [{
          summary: "结尾仍需补充行动建议",
          severity: "中",
          achievements: ["主线结构已经清晰"],
          problems: ["结尾行动指引不足"],
        }],
      }],
      technical: {},
    }} />);
    expect(screen.getByText("问题 · 中")).toBeInTheDocument();
    expect(screen.getAllByText("结尾仍需补充行动建议")).toHaveLength(1);
    expect(screen.getByText("已达成")).toBeInTheDocument();
    expect(screen.getByText("主线结构已经清晰")).toBeInTheDocument();
    expect(screen.getByText("需关注")).toBeInTheDocument();
    expect(screen.getByText("结尾行动指引不足")).toBeInTheDocument();
  });
});
