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

import { emptyDecisions, setVerdict } from "./decisions";
import {
  displayOrder,
  groupConflicts,
  nextUnresolvedInOrder,
} from "./grouping";
import type { ReviewConflict } from "./sse";

function conflict(type: string, suggestion = "x"): ReviewConflict {
  return {
    type,
    where: "",
    refs: [],
    suggestion,
    original: null,
    replacement: null,
  };
}

describe("groupConflicts", () => {
  it("groups by type and carries the original index", () => {
    const conflicts = [
      conflict("性格漂移", "a"),
      conflict("设定违例", "b"),
      conflict("性格漂移", "c"),
    ];
    const groups = groupConflicts(conflicts);
    const drift = groups.find((g) => g.type === "性格漂移");
    expect(drift?.items.map((it) => it.index)).toEqual([0, 2]);
    expect(drift?.items.map((it) => it.conflict.suggestion)).toEqual(["a", "c"]);
  });

  it("orders groups by severity (设定违例 before 性格漂移)", () => {
    const groups = groupConflicts([
      conflict("性格漂移"),
      conflict("设定违例"),
    ]);
    expect(groups.map((g) => g.type)).toEqual(["设定违例", "性格漂移"]);
  });

  it("places unknown types after the known five", () => {
    const groups = groupConflicts([conflict("排版错误"), conflict("能力不符")]);
    expect(groups.map((g) => g.type)).toEqual(["能力不符", "排版错误"]);
  });

  it("returns an empty array for no conflicts", () => {
    expect(groupConflicts([])).toEqual([]);
  });
});

describe("displayOrder", () => {
  it("flattens grouped indices in display order", () => {
    const groups = groupConflicts([
      conflict("性格漂移"),
      conflict("设定违例"),
      conflict("性格漂移"),
    ]);
    // 设定违例(index 1) 先，再 性格漂移(0,2)
    expect(displayOrder(groups)).toEqual([1, 0, 2]);
  });
});

describe("nextUnresolvedInOrder", () => {
  const order = [1, 0, 2];

  it("finds the first unresolved when nothing is focused", () => {
    const drafts = emptyDecisions(3);
    expect(nextUnresolvedInOrder(order, drafts, null)).toBe(1);
  });

  it("advances to the next unresolved after the focused index", () => {
    let drafts = emptyDecisions(3);
    drafts = setVerdict(drafts, 1, "accept");
    expect(nextUnresolvedInOrder(order, drafts, 1)).toBe(0);
  });

  it("wraps around to earlier unresolved items", () => {
    let drafts = emptyDecisions(3);
    drafts = setVerdict(drafts, 2, "ignore");
    expect(nextUnresolvedInOrder(order, drafts, 2)).toBe(1);
  });

  it("returns null when all are resolved", () => {
    let drafts = emptyDecisions(3);
    drafts = setVerdict(drafts, 0, "accept");
    drafts = setVerdict(drafts, 1, "accept");
    drafts = setVerdict(drafts, 2, "accept");
    expect(nextUnresolvedInOrder(order, drafts, null)).toBeNull();
  });

  it("returns null for an empty order", () => {
    expect(nextUnresolvedInOrder([], [], null)).toBeNull();
  });
});
