import { afterEach, describe, expect, it, vi } from "vitest";

import { fetchDraft, fetchOutline } from "./server";

// 纯加载/降级逻辑（mock fetch，无网络/DOM）：大纲解包/降级、草稿 404→null。
function mockFetch(status: number, body: unknown): void {
  vi.stubGlobal(
    "fetch",
    vi.fn(async () =>
      new Response(JSON.stringify(body), {
        status,
        headers: { "content-type": "application/json" },
      }),
    ),
  );
}

afterEach(() => {
  vi.unstubAllGlobals();
});

describe("fetchOutline", () => {
  it("returns the persisted chapters on 200", async () => {
    mockFetch(200, { chapters: [{ no: 1, volume: 1, beats: ["开场"] }] });

    const chapters = await fetchOutline("p1");

    expect(chapters).toHaveLength(1);
    expect(chapters[0]?.no).toBe(1);
  });

  it("returns empty array when the project has no outline", async () => {
    mockFetch(200, { chapters: [] });

    expect(await fetchOutline("p1")).toEqual([]);
  });

  it("falls back to empty array on any error (does not throw)", async () => {
    mockFetch(404, { error: { code: "NOT_FOUND", message: "no project" } });

    expect(await fetchOutline("missing")).toEqual([]);
  });
});

describe("fetchDraft", () => {
  it("returns the saved draft view on 200", async () => {
    mockFetch(200, {
      project_id: "p1",
      chapter_no: 1,
      volume: 1,
      status: "draft",
      version: 2,
      content: "第一章正文",
      length: 5,
    });

    const draft = await fetchDraft("p1", 1);

    expect(draft?.content).toBe("第一章正文");
    expect(draft?.version).toBe(2);
  });

  it("returns null when no draft exists (404 → empty editor)", async () => {
    mockFetch(404, { error: { code: "NOT_FOUND", message: "no draft" } });

    expect(await fetchDraft("p1", 9)).toBeNull();
  });
});
