import { describe, expect, it } from "vitest";
import {
  applyPermissionResponse,
  applyQuestionResponse,
  finalizeAssistantMessageAfterAbort,
  toTodoUpdate,
  upsertPermission,
  upsertProgress,
  upsertQuestion
} from "./session-state";
import type { AgentChatMessage } from "./types";

describe("agent session state", () => {
  it("upserts progress events by id", () => {
    const first = upsertProgress(undefined, {
      id: "tool-1",
      phase: "tool",
      status: "running",
      title: "调用工具",
      elapsed_ms: 20
    });
    const next = upsertProgress(first, {
      id: "tool-1",
      phase: "tool",
      status: "completed",
      title: "工具完成",
      duration_ms: 40
    });

    expect(next).toHaveLength(1);
    expect(next[0]).toMatchObject({ id: "tool-1", status: "completed", title: "工具完成", durationMs: 40 });
  });

  it("normalizes todo updates", () => {
    expect(
      toTodoUpdate({
        session_id: "session-1",
        todos: [{ id: "todo-1", content: "分析压力", status: "in_progress", priority: "high" }],
        created_at: 123
      })
    ).toEqual({
      sessionId: "session-1",
      messageId: undefined,
      todos: [{ id: "todo-1", content: "分析压力", status: "in_progress", priority: "high" }],
      createdAt: 123
    });
  });

  it("tracks permission request and response", () => {
    const permissions = upsertPermission(undefined, {
      session_id: "session-1",
      request_id: "permission-1",
      permission: "bash",
      patterns: ["pnpm test"],
      always: [],
      created_at: 100
    });
    const next = applyPermissionResponse(permissions, {
      request_id: "permission-1",
      reply: "once"
    });

    expect(next?.[0]).toMatchObject({
      requestId: "permission-1",
      status: "approved_once"
    });
  });

  it("dedupes question requests by tool call id", () => {
    const questions = upsertQuestion(undefined, {
      session_id: "session-1",
      request_id: "call-1",
      tool: { messageID: "message-1", callID: "call-1" },
      questions: [{ header: "范围", question: "选择范围", options: [] }],
      created_at: 100
    });
    const next = upsertQuestion(questions, {
      session_id: "session-1",
      request_id: "question-1",
      tool: { messageID: "message-1", callID: "call-1" },
      questions: [{ header: "范围", question: "选择范围", options: [] }],
      created_at: 120
    });
    const answered = applyQuestionResponse(next, {
      request_id: "question-1",
      answers: [["东部"]]
    });

    expect(next).toHaveLength(1);
    expect(answered?.[0]).toMatchObject({
      requestId: "question-1",
      status: "answered",
      answers: [["东部"]]
    });
  });

  it("preserves an actionable question id when its tool placeholder arrives later", () => {
    const questions = upsertQuestion(undefined, {
      session_id: "session-1",
      request_id: "question-1",
      tool: { messageID: "message-1", callID: "call-1" },
      questions: [{ header: "范围", question: "选择范围", options: [] }],
      created_at: 100
    });
    const withPlaceholder = upsertQuestion(questions, {
      session_id: "session-1",
      request_id: "call-1",
      tool: { messageID: "message-1", callID: "call-1" },
      questions: [{ header: "范围", question: "选择范围", options: [] }],
      created_at: 120
    });
    const rejected = applyQuestionResponse(withPlaceholder, {
      request_id: "question-1",
      rejected: true
    });

    expect(withPlaceholder).toHaveLength(1);
    expect(rejected?.[0]).toMatchObject({
      requestId: "question-1",
      status: "rejected"
    });
  });

  it("finalizes open assistant state after abort", () => {
    const message: AgentChatMessage = {
      id: "assistant-1",
      role: "assistant",
      content: "",
      progress: [{ id: "run", phase: "run", status: "running", title: "处理中", startedAt: Date.now() }],
      permissions: [
        {
          requestId: "permission-1",
          sessionId: "session-1",
          permission: "bash",
          patterns: [],
          always: [],
          createdAt: 100,
          status: "pending"
        }
      ]
    };

    const next = finalizeAssistantMessageAfterAbort(message);

    expect(next.content).toBe("请求已中止。");
    expect(next.progress?.[0].status).toBe("completed");
    expect(next.permissions?.[0].status).toBe("aborted");
  });
});
