import { describe, expect, it } from "vitest";
import {
  createChecklistPartId,
  createLocalThinkingPartId,
} from "../src/dimsdk/core/transcript-part-id.ts";
import { createMessagePipeline } from "../src/dimsdk/core/store/message-pipeline.ts";
import { createDimSdkState } from "../src/dimsdk/core/store/state.ts";

function createPipeline() {
  const { state } = createDimSdkState({
    context: { cwd: process.cwd(), env: {} } as any,
    agent: { getMode: () => "agent" } as any,
  });
  const pipeline = createMessagePipeline({
    state,
    debugLog: () => {},
  });
  return { pipeline, state };
}

describe("dimsdk message pipeline collapse targeting", () => {
  it("toggles a thinking block by stable partId even after tool parts insert ahead of it", () => {
    const { pipeline, state } = createPipeline();
    const partId = createLocalThinkingPartId("assistant-collapse-1", 0);

    pipeline.pushMessage({
      id: "assistant-collapse-1",
      role: "assistant",
      parts: [
        { type: "status", text: "" },
        {
          type: "tool_call",
          call: {
            id: "tool_ask_user",
            name: "ask-user",
            arguments: {},
          },
        },
        {
          type: "thinking",
          partId,
          title: "Thinking",
          collapsed: true,
          content: "Reasoning that should expand.",
        },
        {
          type: "tool_call",
          call: {
            id: "tool_web_search",
            name: "web-search",
            arguments: { query: "weather" },
          },
        },
      ],
      createdAtMs: Date.now(),
    });

    pipeline.attachToolResultPart("assistant-collapse-1", {
      output: '{"answer":"Shanghai"}',
      status: "success",
      toolCallId: "tool_ask_user",
    });

    pipeline.toggleBlockCollapsed("assistant-collapse-1", "thinking", partId);

    const assistant = state.messages[0] as any;
    const thinkingParts = assistant.parts.filter((part: any) => part.type === "thinking");

    expect(thinkingParts).toHaveLength(1);
    expect(thinkingParts[0]?.partId).toBe(partId);
    expect(thinkingParts[0]?.collapsed).toBe(false);
    expect(assistant.parts.map((part: any) => part.type)).toEqual([
      "status",
      "tool_call",
      "tool_result",
      "thinking",
      "tool_call",
    ]);
  });

  it("keeps a tool-derived todo block collapsible by stable partId after tool transcript grows", () => {
    const { pipeline, state } = createPipeline();
    const todoPartId = createChecklistPartId("todo", "tool_todo_write");

    pipeline.pushMessage({
      id: "assistant-collapse-2",
      role: "assistant",
      parts: [
        { type: "status", text: "" },
        {
          type: "tool_call",
          call: {
            id: "tool_todo_write",
            name: "TodoWrite",
            arguments: {},
          },
        },
      ],
      createdAtMs: Date.now(),
    });

    pipeline.upsertChecklistPartFromDimSdk(
      "assistant-collapse-2",
      "todo",
      "tool_todo_write",
      {
        todos: [
          { content: "Inspect the failure", status: "in_progress" },
          { content: "Verify the fix", status: "pending" },
        ],
      },
    );

    pipeline.attachToolResultPart("assistant-collapse-2", {
      output: '{"ok":true}',
      status: "success",
      toolCallId: "tool_todo_write",
    });

    pipeline.toggleBlockCollapsed("assistant-collapse-2", "todo", todoPartId);

    const assistant = state.messages[0] as any;
    const todoParts = assistant.parts.filter((part: any) => part.type === "todo");

    expect(todoParts).toHaveLength(1);
    expect(todoParts[0]?.partId).toBe(todoPartId);
    expect(todoParts[0]?.collapsed).toBe(true);
  });

  it("normalizes missing interactive part ids when older assistant messages are loaded", () => {
    const { pipeline, state } = createPipeline();

    pipeline.pushMessage({
      id: "assistant-legacy",
      role: "assistant",
      parts: [
        { type: "status", text: "" },
        {
          type: "thinking",
          title: "Thinking",
          collapsed: true,
          content: "Legacy persisted reasoning.",
        },
      ] as any,
      createdAtMs: Date.now(),
    } as any);

    const assistant = state.messages[0] as any;
    const thinkingPart = assistant.parts.find((part: any) => part.type === "thinking");

    expect(thinkingPart?.partId).toBe(createLocalThinkingPartId("assistant-legacy", 0));
  });
});
