// wedge — acceptance grid for brew-resolve.ts.
//
// Mirror of apt-resolve.test.ts: pure decision logic exercised against real
// `brew list --versions` fixtures and the DARWIN_ALIASES seed map. Caller
// supplies the brewInstalled boolean and the parsed package name; the resolver
// returns the name to feed `brew install` and an optional log line for the
// alias path. Runs identically on Linux CI and Mac developer boxes — no
// spawnSync, no fs reads.
import test from "node:test";
import assert from "node:assert/strict";
import { DARWIN_ALIASES, parseBrewListVersions, decideBrewResolution, } from "../brew-resolve.js";
// ---------------------------------------------------------------------------
// Real fixtures — captured from `brew list --versions` on macOS.
// ---------------------------------------------------------------------------
// Multi-version line — Homebrew keeps prior versions in the cellar until
// `brew cleanup`, so a `--versions` query against a long-lived install can
// return more than one token after the package name. The resolver returns
// every token; the caller decides which version is "current."
const NODE22_MULTI_VERSION = "node@22 22.18.1 22.18.0\n";
// Installed package, single version — the steady-state shape for a fresh install.
const CLOUDFLARED_SINGLE_VERSION = "cloudflared 2025.1.4\n";
// Missing package — `brew list --versions <pkg>` exits 1 with empty stdout.
// The resolver still receives the empty string and must return [] without
// throwing (the install caller decides whether absence is fatal).
const MISSING_STDOUT = "";
// Edge: only the package name with trailing newline (older Homebrew cellars
// can produce this if a formula was uninstalled mid-sequence).
const NAME_ONLY = "node@22\n";
// Edge: whitespace-only stdout (caller piped a stale buffer, etc.).
const WHITESPACE_ONLY = "   \n";
// ---------------------------------------------------------------------------
// parseBrewListVersions — split-and-skip-first-token semantics.
// ---------------------------------------------------------------------------
test("parseBrewListVersions: multi-version line returns every token after pkg name", () => {
    assert.deepEqual(parseBrewListVersions(NODE22_MULTI_VERSION), ["22.18.1", "22.18.0"]);
});
test("parseBrewListVersions: single-version line returns one token", () => {
    assert.deepEqual(parseBrewListVersions(CLOUDFLARED_SINGLE_VERSION), ["2025.1.4"]);
});
test("parseBrewListVersions: empty stdout (pkg missing) returns []", () => {
    assert.deepEqual(parseBrewListVersions(MISSING_STDOUT), []);
});
test("parseBrewListVersions: name-only line returns []", () => {
    assert.deepEqual(parseBrewListVersions(NAME_ONLY), []);
});
test("parseBrewListVersions: whitespace-only stdout returns []", () => {
    // Trip on naïve `.split(' ')[1]` returning ''. Resolver must reject empty
    // tokens, not return [''].
    assert.deepEqual(parseBrewListVersions(WHITESPACE_ONLY), []);
});
// ---------------------------------------------------------------------------
// decideBrewResolution — three branches.
// ---------------------------------------------------------------------------
test("decideBrewResolution: brew-installed pkg returns pkg, no log", () => {
    // Branch 1: caller's brewInstalled probe came back true — name is concrete
    // and present. Return as-is, follow-up's post-check uses the same name.
    const r = decideBrewResolution({
        pkg: "node@22",
        brewInstalled: true,
    });
    assert.equal(r.resolved, "node@22");
    assert.equal(r.log, null);
});
test("decideBrewResolution: alias-mapped pkg returns alias with log line", () => {
    // Branch 2: pkg is in DARWIN_ALIASES — return the brew formula name and
    // emit the diagnostic line installer logs grep on.
    const r = decideBrewResolution({
        pkg: "nodejs",
        brewInstalled: false,
    });
    assert.equal(r.resolved, "node@22");
    assert.match(r.log ?? "", /^  brew-resolve nodejs → node@22 \(reason=darwin-alias\)$/);
});
test("decideBrewResolution: unaliased pkg returns pkg unchanged, no log", () => {
    // Branch 3: not installed AND not in alias map — return pkg unchanged.
    // Preserves the apt-resolve.ts loud-failure contract: the install caller's
    // post-check throws when the package genuinely doesn't exist.
    const r = decideBrewResolution({
        pkg: "cloudflared",
        brewInstalled: false,
    });
    assert.equal(r.resolved, "cloudflared");
    assert.equal(r.log, null);
});
test("decideBrewResolution: brewInstalled=true takes precedence over alias map", () => {
    // Edge: pkg is in the alias map AND already installed under the alias name.
    // brewInstalled=true means the post-check would already pass — return pkg
    // unchanged so the caller doesn't double-resolve.
    const r = decideBrewResolution({
        pkg: "nodejs",
        brewInstalled: true,
    });
    assert.equal(r.resolved, "nodejs");
    assert.equal(r.log, null);
});
// ---------------------------------------------------------------------------
// DARWIN_ALIASES — shape lock. Adding a new alias must be a deliberate edit
// to this test grid, not a silent expansion.
// ---------------------------------------------------------------------------
test("DARWIN_ALIASES contains nodejs → node@22 and is the only entry", () => {
    assert.equal(DARWIN_ALIASES.nodejs, "node@22");
    assert.equal(Object.keys(DARWIN_ALIASES).length, 1);
});
// ---------------------------------------------------------------------------
// DARWIN_BASE_DEPS + neo4j shape lock — every brew dep the darwin install
// branch feeds into installAllBrewPackages must either (a) be a real Homebrew
// core formula already, or (b) resolve to one via DARWIN_ALIASES. The list is
// duplicated here from index.ts:installSystemDeps so a future edit of either
// surface has to keep them in sync.
// ---------------------------------------------------------------------------
// Mirrors `DARWIN_BASE_DEPS` in packages/create-maxy-code/src/index.ts. Every
// entry must be either a real brew formula (pass-through) or an alias.
const DARWIN_BASE_DEPS_FIXTURE = ["curl", "git", "unzip", "jq", "poppler", "ffmpeg", "tesseract", "ocrmypdf"];
// `neo4j` and `cloudflared` are passed to installAllBrewPackages from
// installNeo4j (index.ts:1265) and installCloudflared (index.ts:1728). Both are
// concrete brew formula names — no alias hop expected.
const DARWIN_SOLO_DEPS_FIXTURE = ["neo4j", "cloudflared"];
test("every DARWIN_BASE_DEPS entry passes through the resolver as the brew formula name", () => {
    for (const pkg of DARWIN_BASE_DEPS_FIXTURE) {
        const r = decideBrewResolution({ pkg, brewInstalled: false });
        assert.equal(r.resolved, pkg, `DARWIN_BASE_DEPS entry '${pkg}' must not be aliased`);
        assert.equal(r.log, null, `DARWIN_BASE_DEPS entry '${pkg}' must not emit an alias log line`);
    }
});
test("neo4j and cloudflared pass through unchanged — no alias hop", () => {
    for (const pkg of DARWIN_SOLO_DEPS_FIXTURE) {
        const r = decideBrewResolution({ pkg, brewInstalled: false });
        assert.equal(r.resolved, pkg);
        assert.equal(r.log, null);
    }
});
test("nodejs alias hop resolves to node@22 for darwin install", () => {
    // The shared-dep call site (index.ts:988 installNodejs) passes "nodejs";
    // this test pins the brew-formula landing for that single alias.
    const r = decideBrewResolution({ pkg: "nodejs", brewInstalled: false });
    assert.equal(r.resolved, "node@22");
    assert.match(r.log ?? "", /node@22/);
});
