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

const binding: SourceBinding = {
  id: "result-1",
  sourceId: "event:4607",
  role: "output",
  selector: { kind: "json-pointer", path: "/output/content/results/0" },
  transform: { kind: "direct" },
  evidence: { availability: "returned-to-agent", adoption: "not-recorded", confidence: "exact" },
  resolution: "resolved",
};

const payload: InspectorWorkbenchProjection = {
  schemaVersion: "inspector-source-v2",
  detailRef: "event:4607",
  cardKind: "query",
  completeness: "complete",
  businessProjection: {
    detailKind: "activity",
    businessSections: [{ id: "results", title: "返回结果", items: [{ label: "Case 1", value: "命中内容" }] }],
  },
  modules: [{
    id: "results",
    title: "返回结果",
    businessPath: "/businessSections/0",
    presentation: "items",
    rows: [{ id: "case-1", label: "Case 1", businessSelector: "/businessSections/0/items/0/value", bindingIds: [binding.id] }],
    bindings: [binding],
    runtimeRefs: ["event:4607"],
    defaultOpen: true,
  }],
  sources: {
    "event:4607": {
      id: "event:4607",
      kind: "runtime-event",
      label: "search_script_decode_case",
      locator: { table: "script_build_event + script_build_event_body", eventId: 4607, eventName: "search_script_decode_case" },
      status: "ok",
      completeness: "complete",
      resultState: "present",
      selectedValues: [{ bindingId: binding.id, path: "/output/content/results/0", value: "命中内容" }],
      rawRecord: { output: { content: { results: ["命中内容"] } } },
    },
  },
  notices: [],
};

describe("InspectorComparison", () => {
  it("returns from the source comparison to the readable business Inspector", () => {
    const onModeChange = vi.fn();
    const item = storyItem(makeStory("event:4607", "planning-analysis"), 1);
    render(<Inspector item={item} mode="lineage" onModeChange={onModeChange} onClose={vi.fn()} workbench={payload} />);
    fireEvent.click(screen.getByRole("button", { name: "返回业务详情" }));
    expect(onModeChange).toHaveBeenCalledWith("business");
  });

  it("renders business fields from the same projection used by the readable Inspector", () => {
    const planPayload: InspectorWorkbenchProjection = {
      ...payload,
      detailRef: "round:1:plan",
      cardKind: "implementation-plan",
      businessProjection: {
        detailKind: "agent-decision",
        blocks: [{
          type: "implementation-plan",
          title: "本轮实施路线",
          mode: "竞争",
          reasoning: "比较两条路线。",
          routes: [{ pathIndex: 1, target: "完整段落骨架", method: "产生脉络", emphasis: "先保证结构清楚" }],
        }],
      },
      modules: [{
        id: "block-1",
        title: "本轮实施路线",
        businessPath: "/blocks/0",
        presentation: "plan",
        rows: [
          { id: "mode", label: "规划方式", businessSelector: "/blocks/0/mode", bindingIds: [binding.id] },
          { id: "target", label: "路线 1 · 作用范围", businessSelector: "/blocks/0/routes/0/target", bindingIds: [binding.id] },
          { id: "method", label: "路线 1 · 实施方法", businessSelector: "/blocks/0/routes/0/method", bindingIds: [binding.id] },
          { id: "emphasis", label: "路线 1 · 路线侧重", businessSelector: "/blocks/0/routes/0/emphasis", bindingIds: [binding.id] },
        ],
        bindings: [binding],
        runtimeRefs: [],
        defaultOpen: true,
      }],
    };
    const { container } = render(<InspectorComparison data={planPayload} />);
    expect(screen.getByText("竞争")).toBeInTheDocument();
    expect(screen.getByText("完整段落骨架")).toBeInTheDocument();
    expect(screen.getByText("产生脉络")).toBeInTheDocument();
    expect(screen.getByText("先保证结构清楚")).toBeInTheDocument();
    expect(container.querySelector(".comparisonItemBusiness")?.textContent).not.toContain("pathIndex");
  });

  it("renders one physical row across all three columns", () => {
    const { container } = render(<InspectorComparison data={payload} />);
    expect(screen.getByText("业务详情中的内容")).toBeInTheDocument();
    expect(screen.getByText("这一项的数据依据")).toBeInTheDocument();
    expect(screen.getByText("对应的原始字段或原文")).toBeInTheDocument();
    expect(screen.getByText("返回结果")).toBeInTheDocument();
    expect(screen.getAllByText("S1").length).toBeGreaterThanOrEqual(2);
    expect(screen.getByText("已返回给 Agent，是否采用未记录")).toBeInTheDocument();
    expect(screen.getByText("script_build_event + script_build_event_body")).toBeInTheDocument();
    expect(container.querySelectorAll(".comparisonItemRow")).toHaveLength(1);
  });

  it("shows the exact selected source value without opening raw JSON", () => {
    render(<InspectorComparison data={payload} />);
    expect(screen.getAllByText("命中内容").length).toBeGreaterThanOrEqual(2);
    expect(screen.getByText("完整原始记录")).toBeInTheDocument();
    expect(screen.getByText("/output/content/results/0").closest("details")).not.toHaveAttribute("open");
    expect(screen.queryByText("found")).not.toBeInTheDocument();
  });

  it("keeps structured business rows readable instead of exposing object keys", () => {
    const decisionPayload: InspectorWorkbenchProjection = {
      ...payload,
      cardKind: "data-decision",
      businessProjection: {
        detailKind: "agent-decision",
        blocks: [{
          type: "items",
          title: "参与判断",
          items: [{ label: "解构 Case", value: "返回了 2 条可用案例", note: "已读取" }],
        }],
      },
      modules: [{
        ...payload.modules[0],
        id: "block-1",
        title: "参与判断",
        businessPath: "/blocks/0",
        rows: [{ id: "source-1", label: "解构 Case", businessSelector: "/blocks/0/items/0", bindingIds: [binding.id] }],
      }],
    };
    const { container } = render(<InspectorComparison data={decisionPayload} />);
    const business = container.querySelector(".comparisonItemBusiness");
    expect(business).toHaveTextContent("解构 Case");
    expect(business).toHaveTextContent("返回了 2 条可用案例");
    expect(business).toHaveTextContent("说明");
    expect(business?.textContent).not.toMatch(/\blabel\b|\bvalue\b|\bnote\b/);
  });

  it("synchronizes binding highlight within the already aligned row", () => {
    const onChange = vi.fn();
    const { container } = render(<InspectorComparison data={payload} onActiveBindingChange={onChange} />);
    fireEvent.click(screen.getByRole("button", { name: /已返回给 Agent/ }));
    expect(container.querySelectorAll('[data-binding-id="result-1"]').length).toBeGreaterThanOrEqual(2);
    expect(container.querySelector(".comparisonItemRow.is-active")).toBeInTheDocument();
    expect(onChange).toHaveBeenLastCalledWith("result-1");
  });

  it("unmounts module contents when collapsed", () => {
    render(<InspectorComparison data={payload} />);
    fireEvent.click(screen.getByRole("button", { name: /返回结果/ }));
    expect(screen.queryByText("命中内容")).not.toBeInTheDocument();
  });

  it("explains a successful empty result instead of calling it missing", () => {
    const empty: InspectorWorkbenchProjection = {
      ...payload,
      sources: {
        "event:4607": { ...payload.sources["event:4607"], resultState: "empty", rawRecord: [] },
      },
    };
    render(<InspectorComparison data={empty} />);
    expect(screen.getByText("查询完成，返回 0 条")).toBeInTheDocument();
    expect(screen.getByText("这不是记录缺失。")).toBeInTheDocument();
  });

  it("hands focus control to an upper prompt or artifact overlay", () => {
    const item = storyItem(makeStory("event:4607", "planning-analysis"), 1);
    const onClose = vi.fn();
    const view = (topOverlayOpen: boolean) => <><button type="button" data-testid="upper-overlay-control">上层弹窗按钮</button><Inspector item={item} onClose={onClose} workbench={payload} topOverlayOpen={topOverlayOpen} /></>;
    const { rerender } = render(view(false));
    const outside = screen.getByTestId("upper-overlay-control");
    outside.focus();
    expect(screen.getByRole("dialog")).toContainElement(document.activeElement as HTMLElement);

    rerender(view(true));
    const upperOverlayControl = screen.getByTestId("upper-overlay-control");
    upperOverlayControl.focus();
    expect(document.activeElement).toBe(upperOverlayControl);
  });
});
