import {
  createEmptyChatState,
  deleteChatSession,
  listChatSessions,
  loadChatSessionById,
  updateChatSessionTitle,
} from "./chatStorage";

const apiFetch = jest.fn();

jest.mock("@/lib/apiFetch", () => ({
  apiFetch: (...args: unknown[]) => apiFetch(...args),
}));

describe("chatStorage backend session operations", () => {
  beforeEach(() => {
    apiFetch.mockReset();
  });

  it("creates an empty initial conversation state without backend calls", () => {
    const loaded = createEmptyChatState();

    expect(loaded).toMatchObject({
      title: undefined,
      messages: [],
      sessionId: undefined,
    });
    expect(apiFetch).not.toHaveBeenCalled();
  });

  it("lists backend sessions sorted by created time", async () => {
    apiFetch.mockResolvedValueOnce({
      ok: true,
      json: async () => ({
        sessions: [
          {
            id: "session-old",
            title: "旧会话",
            created_at: "2026-01-01T00:00:00.000Z",
            updated_at: "2026-01-02T00:00:00.000Z",
          },
          {
            id: "session-new",
            title: "新会话",
            created_at: "2026-01-03T00:00:00.000Z",
            updated_at: "2026-01-03T00:00:00.000Z",
            is_streaming: true,
            run_status: "running",
          },
        ],
      }),
    });

    await expect(listChatSessions()).resolves.toEqual([
      expect.objectContaining({
        id: "session-new",
        title: "新会话",
        isStreaming: true,
        runStatus: "running",
      }),
      expect.objectContaining({
        id: "session-old",
        title: "旧会话",
      }),
    ]);
    expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "GET" });
  });

  it("loads a backend session state", async () => {
    apiFetch.mockResolvedValueOnce({
      ok: true,
      json: async () => ({
        id: "session-1",
        title: "管网分析",
        is_title_manually_edited: true,
        messages: [{ id: "message-1", role: "user", content: "查压力" }],
        is_streaming: false,
      }),
    });

    await expect(loadChatSessionById("session-1")).resolves.toMatchObject({
      title: "管网分析",
      isTitleManuallyEdited: true,
      sessionId: "session-1",
      messages: [{ id: "message-1", role: "user", content: "查压力" }],
    });
    expect(String(apiFetch.mock.calls[0][0])).toContain("/sessions/session-1");
    expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "GET" });
  });

  it("updates a backend session title through the title endpoint", async () => {
    apiFetch.mockResolvedValueOnce({
      ok: true,
      text: async () => "",
    });

    await updateChatSessionTitle("session-1", " 新标题 ", {
      isTitleManuallyEdited: true,
    });

    expect(String(apiFetch.mock.calls[0][0])).toContain("/sessions/session-1");
    expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "PATCH" });
    expect(JSON.parse(String(apiFetch.mock.calls[0][1]?.body))).toEqual({
      title: "新标题",
      is_title_manually_edited: true,
    });
  });

  it("deletes a backend session and returns the next active session id", async () => {
    apiFetch
      .mockResolvedValueOnce({
        ok: true,
        text: async () => "",
      })
      .mockResolvedValueOnce({
        ok: true,
        json: async () => ({
          sessions: [
            {
              id: "session-next",
              title: "下一会话",
              created_at: "2026-01-01T00:00:00.000Z",
              updated_at: "2026-01-01T00:00:00.000Z",
            },
          ],
        }),
      });

    await expect(deleteChatSession("session-1")).resolves.toBe("session-next");
    expect(apiFetch.mock.calls[0][1]).toMatchObject({ method: "DELETE" });
    expect(apiFetch.mock.calls[1][1]).toMatchObject({ method: "GET" });
  });
});
