import { expect, test } from "bun:test";

import { mutateMdtodoDocument, parseMdtodoDocument, readMdtodoTaskDetail } from "./mdtodo.ts";

test("parseMdtodoDocument projects Rxx hierarchy without raw body leakage", () => {
  const document = parseMdtodoDocument(`# Demo

## R1 Root task [Processing]

Root notes with [context](https://example.test/context).

### R1.1 Child done [Finished]

- implementation notes stay in source markdown

## R2 Backlog item
`, {
    sourceId: "demo",
    relativePath: "project-management/MDTODO.md"
  });

  expect(document.parserMode).toBe("rxx");
  expect(document.taskCount).toBe(3);
  expect(document.tasks.map((task) => task.taskId)).toEqual(["R1", "R1.1", "R2"]);
  expect(document.tasks.map((task) => task.status)).toEqual(["in_progress", "completed", "open"]);
  expect(document.tasks[1].parentTaskRef).toBe(document.tasks[0].taskRef);
  expect(document.tasks[0].depth).toBe(0);
  expect(document.tasks[1].depth).toBe(1);
  expect(document.tasks[0].linkCount).toBe(1);
  expect(document.tasks[0].links).toEqual([
    expect.objectContaining({ label: "context", kind: "external", relativePath: null })
  ]);
  expect(document.tasks[0].bodyPreview).toBe("Root notes with [context](https://example.test/context).");
  expect(document.tasks[0].body).toBeUndefined();
  expect(document.tasks[0].rawContent).toBeUndefined();
  expect(document.document.parserMode).toBe("rxx");
  expect(document.document.valuesRedacted).toBe(true);
});

test("readMdtodoTaskDetail exposes Rxx body and safe Markdown report links", () => {
  const detail = readMdtodoTaskDetail(`# Demo

## R1 Root task

Task details

- report: [R1.1](./20260110_LOG/R1.1_log_implementation.md)
- external: [context](https://example.test/context)

### R1.1 Child

Child details
`, {
    sourceId: "demo",
    relativePath: "20260609_feedback.md",
    taskRef: "mdtodo:demo:file_plan:R1",
    fileRef: "file_plan",
    projectId: "project_test"
  });

  expect(detail?.body).toContain("Task details");
  expect(detail?.body).not.toContain("Child details");
  expect(detail?.links.find((link) => link.label === "R1.1")).toMatchObject({
    kind: "markdown-report",
    relativePath: "20260110_LOG/R1.1_log_implementation.md"
  });
  expect(detail?.links.find((link) => link.label === "context")).toMatchObject({ kind: "external", relativePath: null });
});

test("parseMdtodoDocument keeps legacy checkbox parsing explicit", () => {
  const document = parseMdtodoDocument(`# Demo

- [ ] Root task
  - [x] Child done
- [-] Blocked item
`, {
    sourceId: "demo",
    relativePath: "project-management/MDTODO.md"
  });

  expect(document.parserMode).toBe("legacy-checkbox");
  expect(document.taskCount).toBe(3);
  expect(document.tasks[0].status).toBe("open");
  expect(document.tasks[1].status).toBe("completed");
  expect(document.tasks[1].parentTaskRef).toBe(document.tasks[0].taskRef);
  expect(document.tasks[2].status).toBe("open");
  expect(document.document.valuesRedacted).toBe(true);
});

test("mutateMdtodoDocument supports Rxx add update delete operations", () => {
  const initial = `# Demo

## R1 Root task

Original body.

### R1.1 Existing child
`;

  let result = mutateMdtodoDocument(initial, { type: "addTask", title: "Second root" });
  expect(result.ok).toBe(true);
  expect(result.changedTaskId).toBe("R2");
  expect(result.markdown).toContain("## R2 Second root");

  result = mutateMdtodoDocument(result.markdown, { type: "addTask", parentRxxId: "R1", title: "Second child", body: "Child body" });
  expect(result.changedTaskId).toBe("R1.2");
  expect(result.markdown).toContain("### R1.2 Second child\n\nChild body");

  result = mutateMdtodoDocument(result.markdown, { type: "addTask", afterRxxId: "R1.1", title: "Continue child" });
  expect(result.changedTaskId).toBe("R1.3");
  expect(result.markdown).toContain("### R1.3 Continue child");

  result = mutateMdtodoDocument(result.markdown, { type: "updateStatus", rxxId: "R1", status: "completed" });
  expect(result.markdown).toContain("## R1 Root task [completed]");

  result = mutateMdtodoDocument(result.markdown, { type: "updateTitle", rxxId: "R1", title: "Renamed root" });
  expect(result.markdown).toContain("## R1 Renamed root [completed]");

  result = mutateMdtodoDocument(result.markdown, { type: "updateBody", rxxId: "R1", body: "Rewritten body." });
  expect(result.markdown).toContain("## R1 Renamed root [completed]\n\nRewritten body.\n\n### R1.1 Existing child");

  result = mutateMdtodoDocument(result.markdown, { type: "deleteTask", rxxId: "R1.2" });
  expect(result.affectedTaskIds).toEqual(["R1.2"]);
  expect(result.markdown).not.toContain("R1.2");
  expect(result.document.tasks.map((task) => task.taskId)).toEqual(["R1", "R1.1", "R1.3", "R2"]);
});

test("mutateMdtodoDocument reports optimistic revision conflicts", () => {
  const conflict = mutateMdtodoDocument("# Demo\n\n## R1 Root\n", {
    type: "updateTitle",
    rxxId: "R1",
    title: "No write",
    expectedFingerprint: "stale"
  });

  expect(conflict.ok).toBe(false);
  expect(conflict.conflict).toBe(true);
  expect(conflict.code).toBe("revision_conflict");
});
