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

import {
  allResolved,
  buildAcceptRequest,
  emptyDecisions,
  missingConflictIndices,
  setNote,
  setVerdict,
  unresolvedIndices,
} from "./decisions";

describe("emptyDecisions", () => {
  it("creates N unresolved drafts", () => {
    expect(emptyDecisions(2)).toEqual([
      { verdict: null, note: "" },
      { verdict: null, note: "" },
    ]);
  });
});

describe("setVerdict / setNote (immutable)", () => {
  it("sets verdict at index without mutating others", () => {
    const drafts = emptyDecisions(2);
    const next = setVerdict(drafts, 1, "ignore");
    expect(next[1]?.verdict).toBe("ignore");
    expect(next[0]?.verdict).toBeNull();
    expect(drafts[1]?.verdict).toBeNull(); // 原数组不变
  });

  it("sets note at index", () => {
    const drafts = emptyDecisions(1);
    const next = setNote(drafts, 0, "手改说明");
    expect(next[0]?.note).toBe("手改说明");
    expect(drafts[0]?.note).toBe("");
  });
});

describe("allResolved / unresolvedIndices", () => {
  it("zero conflicts pass through (allResolved true)", () => {
    expect(allResolved([])).toBe(true);
    expect(unresolvedIndices([])).toEqual([]);
  });

  it("requires every conflict to have a verdict", () => {
    let drafts = emptyDecisions(3);
    expect(allResolved(drafts)).toBe(false);
    expect(unresolvedIndices(drafts)).toEqual([0, 1, 2]);
    drafts = setVerdict(drafts, 0, "accept");
    drafts = setVerdict(drafts, 2, "manual");
    expect(allResolved(drafts)).toBe(false);
    expect(unresolvedIndices(drafts)).toEqual([1]);
    drafts = setVerdict(drafts, 1, "ignore");
    expect(allResolved(drafts)).toBe(true);
    expect(unresolvedIndices(drafts)).toEqual([]);
  });
});

describe("buildAcceptRequest", () => {
  it("includes only resolved decisions and trims notes", () => {
    let drafts = emptyDecisions(3);
    drafts = setVerdict(drafts, 0, "accept");
    drafts = setVerdict(drafts, 2, "manual");
    drafts = setNote(drafts, 2, "  改成后天淬炼  ");
    // index 1 仍未决 → 不应进入请求
    const req = buildAcceptRequest("终稿正文", drafts);
    expect(req.final_text).toBe("终稿正文");
    expect(req.decisions).toEqual([
      { conflict_index: 0, verdict: "accept" },
      { conflict_index: 2, verdict: "manual", note: "改成后天淬炼" },
    ]);
  });

  it("omits empty/whitespace-only notes", () => {
    let drafts = emptyDecisions(1);
    drafts = setVerdict(drafts, 0, "ignore");
    drafts = setNote(drafts, 0, "   ");
    const req = buildAcceptRequest("t", drafts);
    expect(req.decisions).toEqual([{ conflict_index: 0, verdict: "ignore" }]);
  });
});

describe("missingConflictIndices", () => {
  it("extracts a set from 409 details", () => {
    const set = missingConflictIndices({
      missing_conflict_indices: [1, 3],
      conflict_count: 4,
    });
    expect(set.has(1)).toBe(true);
    expect(set.has(3)).toBe(true);
    expect(set.has(0)).toBe(false);
  });

  it("returns empty set for malformed/missing details", () => {
    expect(missingConflictIndices(null).size).toBe(0);
    expect(missingConflictIndices({}).size).toBe(0);
    expect(missingConflictIndices({ missing_conflict_indices: "x" }).size).toBe(
      0,
    );
  });
});
