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

import {
  canAdvance,
  canSubmit,
  clampStep,
  emptyWizardForm,
  STEP_TITLES,
  toCreateRequest,
  WIZARD_STEPS,
  type WizardForm,
} from "./wizard";

describe("wizard step metadata", () => {
  it("provides one title per step", () => {
    expect(STEP_TITLES).toHaveLength(WIZARD_STEPS);
  });

  it("ends on a confirmation step rather than an empty world step", () => {
    expect(STEP_TITLES[WIZARD_STEPS - 1]).toBe("确认与提交");
  });
});

describe("wizard step gating", () => {
  it("blocks advancing past step 1 without a title", () => {
    expect(canAdvance(1, emptyWizardForm)).toBe(false);
  });

  it("allows advancing step 1 once title is set", () => {
    expect(canAdvance(1, { ...emptyWizardForm, title: "逐光而行" })).toBe(true);
  });

  it("allows advancing later steps even when fields are empty", () => {
    expect(canAdvance(3, emptyWizardForm)).toBe(true);
  });

  it("clamps step within bounds", () => {
    expect(clampStep(0)).toBe(1);
    expect(clampStep(WIZARD_STEPS + 3)).toBe(WIZARD_STEPS);
    expect(clampStep(3)).toBe(3);
  });

  it("requires a title to submit", () => {
    expect(canSubmit(emptyWizardForm)).toBe(false);
    expect(canSubmit({ ...emptyWizardForm, title: "x" })).toBe(true);
  });
});

describe("toCreateRequest", () => {
  it("maps form to snake_case request, nulling empty optionals", () => {
    const form: WizardForm = {
      title: "  逐光而行  ",
      genre: "玄幻",
      logline: "",
      sellingPoints: ["逆袭", "系统流"],
      structure: "三幕",
      premise: "  ",
      protagonist: "",
      theme: "抗争",
    };
    expect(toCreateRequest(form)).toEqual({
      title: "逐光而行",
      genre: "玄幻",
      logline: null,
      premise: null,
      theme: "抗争",
      selling_points: ["逆袭", "系统流"],
      structure: "三幕",
    });
  });

  // QA H1 回归：立意（premise）与主角/金手指（protagonist）是两个独立输入，
  // 不能互相覆盖——提交时各占一段合并进 premise。
  it("merges premise and protagonist into premise without overwriting", () => {
    const form: WizardForm = {
      ...emptyWizardForm,
      title: "书",
      premise: "凡人逆袭的代价",
      protagonist: "主角林川，金手指=吞噬术，限制：每次吞噬折寿",
    };
    const req = toCreateRequest(form);
    expect(req.premise).toBe(
      "凡人逆袭的代价\n\n主角/金手指：主角林川，金手指=吞噬术，限制：每次吞噬折寿",
    );
  });

  it("keeps protagonist alone when premise is empty", () => {
    const form: WizardForm = {
      ...emptyWizardForm,
      title: "书",
      protagonist: "主角设定",
    };
    expect(toCreateRequest(form).premise).toBe("主角/金手指：主角设定");
  });
});

// wizard→create 流程：归一后的请求体经 mock 客户端提交，返回新建项目 id。
describe("wizard create flow (mocked client)", () => {
  it("submits the normalized body and resolves a project id", async () => {
    const post = async (
      _path: string,
      opts: { body: ReturnType<typeof toCreateRequest> },
    ): Promise<{ data: { id: string }; error: null }> => {
      expect(opts.body.title).toBe("青冥录");
      expect(opts.body.selling_points).toEqual(["群像"]);
      return { data: { id: "proj-123" }, error: null };
    };

    const form: WizardForm = {
      ...emptyWizardForm,
      title: "青冥录",
      sellingPoints: ["群像"],
    };
    const { data } = await post("/projects", { body: toCreateRequest(form) });
    expect(data.id).toBe("proj-123");
  });
});
