import assert from "node:assert/strict";
import test from "node:test";
import {
  buildChapterSegments,
  mergeAdjacentChapters,
  splitChapter,
} from "../../lib/domain/chapters.ts";

const chapter = {
  id: "chapter-1",
  title: "第一章",
  position: 0,
  pageStart: 1,
  pageEnd: 2,
  blocks: [
    { id: "b1", text: "第一句。第二句！", kind: "prose", included: true, pageNumber: 1 },
    { id: "b2", text: "E = mc² + ∑ αᵢ", kind: "formula", included: false, pageNumber: 1 },
    { id: "b3", text: "This is chapter one.", kind: "prose", included: true, pageNumber: 2 },
  ],
};

test("builds stable sentence segments and excludes skipped blocks", async () => {
  const first = await buildChapterSegments(chapter);
  const second = await buildChapterSegments(structuredClone(chapter));

  assert.deepEqual(first, second);
  assert.deepEqual(first.map(({ text }) => text), ["第一句。", "第二句！", "E = mc² + ∑ αᵢ", "This is chapter one."]);
  assert.deepEqual(first.map(({ language }) => language), ["zh-CN", "zh-CN", "en-US", "en-US"]);
  assert.equal(first.every((segment) => segment.id.startsWith("seg-")), true);
  assert.equal(first.find((segment) => segment.text.includes("mc")).included, false);
  assert.equal(first.find((segment) => segment.text.includes("mc")).warning, "formula");
});

test("changing one sentence preserves stable IDs and changes only its content hash", async () => {
  const before = await buildChapterSegments(chapter);
  const edited = structuredClone(chapter);
  edited.blocks[0].text = "第一句已修改。第二句！";
  const after = await buildChapterSegments(edited);

  assert.equal(after[0].id, before[0].id);
  assert.notEqual(after[0].contentHash, before[0].contentHash);
  assert.equal(after[1].id, before[1].id);
  assert.equal(after[1].contentHash, before[1].contentHash);
  assert.equal(after[2].id, before[2].id);
  assert.equal(after[3].id, before[3].id);
});

test("splits a chapter at a block boundary and renumbers both halves", () => {
  const [left, right] = splitChapter(chapter, "b3", "第二部分");
  assert.equal(left.title, "第一章");
  assert.equal(right.title, "第二部分");
  assert.deepEqual(left.blocks.map(({ id }) => id), ["b1", "b2"]);
  assert.deepEqual(right.blocks.map(({ id }) => id), ["b3"]);
  assert.equal(left.pageEnd, 1);
  assert.equal(right.pageStart, 2);
  assert.throws(() => splitChapter(chapter, "b1", "bad"), /第一段之前拆分/);
});

test("merges only adjacent chapters while retaining ordered blocks", () => {
  const next = {
    ...chapter,
    id: "chapter-2",
    title: "第二章",
    position: 1,
    pageStart: 3,
    pageEnd: 4,
    blocks: [{ id: "b4", text: "下一章。", kind: "prose", included: true, pageNumber: 3 }],
  };
  const merged = mergeAdjacentChapters(chapter, next, "合并章节");
  assert.equal(merged.title, "合并章节");
  assert.deepEqual(merged.blocks.map(({ id }) => id), ["b1", "b2", "b3", "b4"]);
  assert.equal(merged.pageStart, 1);
  assert.equal(merged.pageEnd, 4);
  assert.throws(() => mergeAdjacentChapters(chapter, { ...next, position: 3 }, "bad"), /相邻章节/);
});
