import { describe, expect, it } from "bun:test";
import { type CalculatedDeadline } from "./views/verfahrensablauf-core";
import { filterByDetailMode, isRuleSelected } from "./verfahrensablauf-detail-mode";

// Helper — minimum-viable CalculatedDeadline for unit testing the filter
// (the renderer's other fields don't matter to the filter).
function mkRule(
  ruleId: string,
  priority: "mandatory" | "recommended" | "optional",
  extras: Partial<CalculatedDeadline> = {},
): CalculatedDeadline {
  return {
    ruleId,
    code: ruleId,
    name: ruleId,
    nameEN: ruleId,
    party: "",
    priority,
    ruleRef: "",
    dueDate: "2026-06-01",
    originalDate: "2026-06-01",
    wasAdjusted: false,
    isRootEvent: false,
    isCourtSet: false,
    ...extras,
  };
}

describe("isRuleSelected", () => {
  it("mandatory rules are always selected, even with explicit deselect", () => {
    const dl = mkRule("a", "mandatory");
    expect(isRuleSelected(dl, null)).toBe(true);
    expect(isRuleSelected(dl, { "rule:a": false })).toBe(true);
  });

  it("recommended rules default to selected; explicit false deselects", () => {
    const dl = mkRule("a", "recommended");
    expect(isRuleSelected(dl, null)).toBe(true);
    expect(isRuleSelected(dl, {})).toBe(true);
    expect(isRuleSelected(dl, { "rule:a": false })).toBe(false);
    expect(isRuleSelected(dl, { "rule:a": true })).toBe(true);
  });

  it("optional rules default to unselected; explicit true selects", () => {
    const dl = mkRule("a", "optional");
    expect(isRuleSelected(dl, null)).toBe(false);
    expect(isRuleSelected(dl, {})).toBe(false);
    expect(isRuleSelected(dl, { "rule:a": true })).toBe(true);
    expect(isRuleSelected(dl, { "rule:a": false })).toBe(false);
  });

  it("conditional rules are treated as unselected in 'Gewählt' (engine left them unprojected)", () => {
    const dl = mkRule("a", "mandatory", { isConditional: true });
    expect(isRuleSelected(dl, null)).toBe(false);
  });
});

describe("filterByDetailMode", () => {
  const deadlines = [
    mkRule("anchor", "mandatory", { isRootEvent: true }),
    mkRule("m1", "mandatory"),
    mkRule("r1", "recommended"),
    mkRule("o1", "optional"),
    mkRule("o2", "optional"),
  ];

  it("mandatory_only returns mandatory + root only", () => {
    const out = filterByDetailMode(deadlines, "mandatory_only", null);
    const ids = out.map((d) => d.ruleId);
    expect(ids).toEqual(["anchor", "m1"]);
  });

  it("selected (default flags) returns mandatory + recommended + root", () => {
    const out = filterByDetailMode(deadlines, "selected", null);
    const ids = out.map((d) => d.ruleId);
    expect(ids).toEqual(["anchor", "m1", "r1"]);
  });

  it("selected with explicit per-rule overrides flips both directions", () => {
    const flags = { "rule:r1": false, "rule:o1": true };
    const out = filterByDetailMode(deadlines, "selected", flags);
    const ids = out.map((d) => d.ruleId);
    expect(ids).toEqual(["anchor", "m1", "o1"]);
  });

  it("all_options returns the full list and tags unselected rules", () => {
    const out = filterByDetailMode(deadlines, "all_options", null);
    expect(out.length).toBe(5);
    const unselected = out.filter(
      (d) => (d as CalculatedDeadline & { __detailUnselected?: boolean }).__detailUnselected,
    );
    // Root + mandatory + recommended are selected; the two optionals
    // are unselected → 2 tagged rows.
    expect(unselected.map((d) => d.ruleId).sort()).toEqual(["o1", "o2"]);
  });
});
