import { mkdirSync, mkdtempSync, realpathSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import {
  assertMandatoryExtensionsLoaded,
  extensionPathMatches,
  normalizeMandatoryExtensionPaths,
} from "../src/mandatory-extensions.js";

function fixturePath(name = "permission-system.ts"): string {
  const dir = mkdtempSync(join(tmpdir(), "pi-subagents-mandatory-"));
  const path = join(dir, name);
  writeFileSync(path, "export default () => {};\n");
  return path;
}

describe("mandatory extension paths", () => {
  it("requires absolute existing extension entries and canonicalizes duplicates", () => {
    const path = fixturePath();
    expect(normalizeMandatoryExtensionPaths([path, path])).toEqual([
      realpathSync.native(path),
    ]);
    expect(() => normalizeMandatoryExtensionPaths(["relative.ts"]))
      .toThrow("must be absolute");
    expect(() => normalizeMandatoryExtensionPaths([join(tmpdir(), "missing-extension.ts")]))
      .toThrow("is unavailable");
  });

  it("accepts extension directories", () => {
    const dir = mkdtempSync(join(tmpdir(), "pi-subagents-mandatory-dir-"));
    const extensionDir = join(dir, "permission-system");
    mkdirSync(extensionDir);
    expect(normalizeMandatoryExtensionPaths([extensionDir])).toEqual([
      realpathSync.native(extensionDir),
    ]);
  });

  it("matches the exact canonical entry rather than a same-named impostor", () => {
    const trusted = fixturePath();
    const impostor = fixturePath();
    const [canonical] = normalizeMandatoryExtensionPaths([trusted]);
    expect(extensionPathMatches(trusted, canonical)).toBe(true);
    expect(extensionPathMatches(impostor, canonical)).toBe(false);
  });

  it("fails closed when the exact mandatory entry did not survive reload", () => {
    const trusted = fixturePath();
    const impostor = fixturePath();
    const mandatory = normalizeMandatoryExtensionPaths([trusted]);
    expect(() => assertMandatoryExtensionsLoaded([impostor], mandatory))
      .toThrow(`Mandatory extension failed to load: ${mandatory[0]}`);
    expect(() => assertMandatoryExtensionsLoaded([trusted], mandatory)).not.toThrow();
  });
});
