import { describe, expect, it } from "vitest";
import { PLACEHOLDER_OWNER_TEAM } from "../../constants.js";
import { evaluateProvenance, mergeProvenancePolicy, SERVER_FLOOR, suggestKnownTeam, } from "../provenance-policy.js";
/** Convenience: the set of violation codes a verdict produced. */
function codesOf(input, policy = SERVER_FLOOR) {
    return evaluateProvenance(input, policy).violations.map((v) => v.code);
}
describe("evaluateProvenance — team baseline (SERVER_FLOOR)", () => {
    it("flags an empty team as team_missing (error)", () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_missing",
        ]);
        expect(verdict.violations[0].severity).toBe("error");
        expect(verdict.normalizedTeam).toBeUndefined();
    });
    it("flags an absent owner as team_missing (error)", () => {
        const verdict = evaluateProvenance({ classification: "adhoc" }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(codesOf({ classification: "adhoc" })).toStrictEqual(["team_missing"]);
    });
    it("flags the init placeholder as team_placeholder (error)", () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: PLACEHOLDER_OWNER_TEAM } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_placeholder",
        ]);
        expect(verdict.normalizedTeam).toBeUndefined();
    });
    it('flags the literal "unknown" sentinel as team_missing (error)', () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "unknown" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_missing",
        ]);
    });
    it('flags a non-slug value ("Bad Slug") as team_malformed (error)', () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "Bad Slug" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_malformed",
        ]);
        expect(verdict.normalizedTeam).toBeUndefined();
    });
    it("folds an alias to its canonical slug (core-docs → docs) with no violation", () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "core-docs" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(true);
        expect(verdict.violations).toStrictEqual([]);
        expect(verdict.normalizedTeam).toBe("docs");
    });
});
describe("evaluateProvenance — non-official unknown slugs (soft)", () => {
    it("soft-warns an unknown but well-formed slug and stays ok", () => {
        const verdict = evaluateProvenance({ classification: "external", owner: { team: "acme-docs" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(true);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_unknown_soft",
        ]);
        expect(verdict.violations[0].severity).toBe("warn");
        expect(verdict.normalizedTeam).toBe("acme-docs");
    });
    it("does not warn for a known slug on a non-official run", () => {
        const verdict = evaluateProvenance({ classification: "experimental", owner: { team: "studio" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(true);
        expect(verdict.violations).toStrictEqual([]);
        expect(verdict.normalizedTeam).toBe("studio");
    });
});
describe("evaluateProvenance — official tier", () => {
    it("rejects an unknown team with a did-you-mean (dcos → docs)", () => {
        const verdict = evaluateProvenance({
            classification: "official",
            owner: { team: "dcos", individual: "a@sanity.io" },
        }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "team_unknown_for_official",
        ]);
        expect(verdict.violations[0].message).toContain('Did you mean "docs"?');
        expect(verdict.normalizedTeam).toBe("dcos");
    });
    it("requires individual on official runs (individual_missing_for_official)", () => {
        const verdict = evaluateProvenance({ classification: "official", owner: { team: "docs" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "individual_missing_for_official",
        ]);
    });
    it("accepts a known team + individual on an official run", () => {
        const verdict = evaluateProvenance({
            classification: "official",
            owner: { team: "docs", individual: "gabe.wyatt@sanity.io" },
        }, SERVER_FLOOR);
        expect(verdict.ok).toBe(true);
        expect(verdict.violations).toStrictEqual([]);
        expect(verdict.normalizedTeam).toBe("docs");
    });
    it("reports both team and individual errors for an unknown-team official run with no individual", () => {
        const verdict = evaluateProvenance({ classification: "official", owner: { team: "dcos" } }, SERVER_FLOOR);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code).sort()).toStrictEqual([
            "individual_missing_for_official",
            "team_unknown_for_official",
        ]);
    });
});
describe("evaluateProvenance — remediation (AC#5)", () => {
    it("names every fix surface and the teams command on a team violation", () => {
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "" } }, SERVER_FLOOR);
        const { remediation } = verdict.violations[0];
        expect(remediation).toContain("--owner-team");
        expect(remediation).toContain("AILF_OWNER_TEAM");
        expect(remediation).toContain(".ailf/ailf.config.ts");
        expect(remediation).toContain("npx @sanity/ailf teams");
    });
});
describe("suggestKnownTeam", () => {
    it("suggests the nearest known slug for a close typo", () => {
        expect(suggestKnownTeam("dcos")).toBe("docs");
        expect(suggestKnownTeam("studioo")).toBe("studio");
        expect(suggestKnownTeam("datta")).toBe("data");
    });
    it("returns undefined when nothing is close enough", () => {
        expect(suggestKnownTeam("zzzzzzzzzz")).toBeUndefined();
    });
    it("returns undefined for an already-known slug (not a misspelling)", () => {
        expect(suggestKnownTeam("docs")).toBeUndefined();
        expect(suggestKnownTeam("studio")).toBeUndefined();
    });
});
describe("mergeProvenancePolicy — strengthen only", () => {
    it("returns a structural copy of the floor when no project policy is given", () => {
        const merged = mergeProvenancePolicy(SERVER_FLOOR);
        expect(merged).toStrictEqual(SERVER_FLOOR);
        expect(merged.rules).not.toBe(SERVER_FLOOR.rules);
    });
    it("cannot lower team below the floor's error", () => {
        const merged = mergeProvenancePolicy(SERVER_FLOOR, { team: "off" });
        expect(merged.team).toBe("error");
    });
    it("lets a project raise individual to error", () => {
        const merged = mergeProvenancePolicy(SERVER_FLOOR, { individual: "error" });
        expect(merged.individual).toBe("error");
    });
    it("unions rules — a project rule is added, the floor rule is kept", () => {
        const projectRule = {
            when: { classification: "experimental" },
            require: { team: "known" },
        };
        const merged = mergeProvenancePolicy(SERVER_FLOOR, { rules: [projectRule] });
        expect(merged.rules).toStrictEqual([...SERVER_FLOOR.rules, projectRule]);
    });
    it("enforces a project-raised individual requirement on a non-official run", () => {
        const merged = mergeProvenancePolicy(SERVER_FLOOR, { individual: "error" });
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "docs" } }, merged);
        expect(verdict.ok).toBe(false);
        expect(verdict.violations.map((v) => v.code)).toStrictEqual([
            "individual_missing",
        ]);
    });
    it("treats the classification severity as inert (condition key only)", () => {
        const merged = mergeProvenancePolicy(SERVER_FLOOR, {
            classification: "error",
        });
        expect(merged.classification).toBe("error");
        const verdict = evaluateProvenance({ classification: "adhoc", owner: { team: "docs" } }, merged);
        expect(verdict.ok).toBe(true);
        expect(verdict.violations).toStrictEqual([]);
    });
});
describe("SERVER_FLOOR is frozen", () => {
    it("cannot be mutated in place", () => {
        expect(Object.isFrozen(SERVER_FLOOR)).toBe(true);
        expect(Object.isFrozen(SERVER_FLOOR.rules)).toBe(true);
        expect(() => {
            SERVER_FLOOR.rules.push({
                when: { classification: "test" },
                require: {},
            });
        }).toThrow();
    });
});
