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

import { buildTurnDiffTree, summarizeTurnDiffStats } from "./turnDiffTree";

describe("summarizeTurnDiffStats", () => {
  it("sums only files with numeric additions/deletions", () => {
    const stat = summarizeTurnDiffStats([
      { path: "README.md", additions: 3, deletions: 1 },
      { path: "docs/notes.md" },
      { path: "src/index.ts", additions: 5, deletions: 2 },
    ]);

    expect(stat).toEqual({ additions: 8, deletions: 3 });
  });
});

describe("buildTurnDiffTree", () => {
  it("builds nested directory nodes with aggregated stats", () => {
    const tree = buildTurnDiffTree([
      { path: "src/index.ts", additions: 2, deletions: 1 },
      { path: "src/components/Button.tsx", additions: 4, deletions: 2 },
      { path: "README.md", additions: 1, deletions: 0 },
    ]);

    expect(tree).toEqual([
      {
        kind: "directory",
        name: "src",
        path: "src",
        stat: { additions: 6, deletions: 3 },
        children: [
          {
            kind: "directory",
            name: "components",
            path: "src/components",
            stat: { additions: 4, deletions: 2 },
            children: [
              {
                kind: "file",
                name: "Button.tsx",
                path: "src/components/Button.tsx",
                stat: { additions: 4, deletions: 2 },
              },
            ],
          },
          {
            kind: "file",
            name: "index.ts",
            path: "src/index.ts",
            stat: { additions: 2, deletions: 1 },
          },
        ],
      },
      {
        kind: "file",
        name: "README.md",
        path: "README.md",
        stat: { additions: 1, deletions: 0 },
      },
    ]);
  });

  it("keeps files without stat values and excludes them from directory totals", () => {
    const tree = buildTurnDiffTree([
      { path: "docs/notes.md" },
      { path: "docs/todo.md", additions: 1, deletions: 1 },
    ]);

    expect(tree).toEqual([
      {
        kind: "directory",
        name: "docs",
        path: "docs",
        stat: { additions: 1, deletions: 1 },
        children: [
          {
            kind: "file",
            name: "notes.md",
            path: "docs/notes.md",
            stat: null,
          },
          {
            kind: "file",
            name: "todo.md",
            path: "docs/todo.md",
            stat: { additions: 1, deletions: 1 },
          },
        ],
      },
    ]);
  });

  it("normalizes file paths with windows separators", () => {
    const tree = buildTurnDiffTree([
      { path: "apps\\web\\src\\index.ts", additions: 2, deletions: 1 },
    ]);

    expect(tree).toEqual([
      {
        kind: "directory",
        name: "apps/web/src",
        path: "apps/web/src",
        stat: { additions: 2, deletions: 1 },
        children: [
          {
            kind: "file",
            name: "index.ts",
            path: "apps/web/src/index.ts",
            stat: { additions: 2, deletions: 1 },
          },
        ],
      },
    ]);
  });

  it("compacts only single-directory chains and stops at branch points", () => {
    const tree = buildTurnDiffTree([
      { path: "apps/server/src/index.ts", additions: 2, deletions: 1 },
      { path: "apps/server/main.ts", additions: 4, deletions: 0 },
    ]);

    expect(tree).toEqual([
      {
        kind: "directory",
        name: "apps/server",
        path: "apps/server",
        stat: { additions: 6, deletions: 1 },
        children: [
          {
            kind: "directory",
            name: "src",
            path: "apps/server/src",
            stat: { additions: 2, deletions: 1 },
            children: [
              {
                kind: "file",
                name: "index.ts",
                path: "apps/server/src/index.ts",
                stat: { additions: 2, deletions: 1 },
              },
            ],
          },
          {
            kind: "file",
            name: "main.ts",
            path: "apps/server/main.ts",
            stat: { additions: 4, deletions: 0 },
          },
        ],
      },
    ]);
  });

  it("preserves leading/trailing whitespace in path segments", () => {
    const tree = buildTurnDiffTree([
      { path: "a/file.ts", additions: 1, deletions: 0 },
      { path: " a/file.ts", additions: 2, deletions: 0 },
    ]);

    expect(tree).toHaveLength(2);
    const directoryNodes = tree.filter(
      (node): node is Extract<(typeof tree)[number], { kind: "directory" }> =>
        node.kind === "directory",
    );
    expect(directoryNodes.map((node) => node.name).toSorted()).toEqual([" a", "a"]);
    expect(directoryNodes.map((node) => node.path).toSorted()).toEqual([" a", "a"]);
  });
});
