// @vitest-environment node

import { mkdtemp, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
  PCRE2_LOCK,
  parsePcre2BuildArguments,
  verifyPcre2Pack,
} from "./pcre2-engine-pack.mjs";

const temporaryDirectories: string[] = [];

afterEach(async () => {
  await Promise.all(
    temporaryDirectories
      .splice(0)
      .map((directory) => rm(directory, { recursive: true, force: true })),
  );
});

describe("PCRE2 engine-pack gate", () => {
  it("keeps the default build on the checked-in production-assets path", () => {
    expect(parsePcre2BuildArguments([])).toEqual({ mode: "ecmascript" });
  });

  it("requires explicit offline source and compiler paths", () => {
    expect(() => parsePcre2BuildArguments(["--pcre2"])).toThrow(
      "requires both --source-dir and --emcc",
    );
    expect(() =>
      parsePcre2BuildArguments([
        "--source-dir",
        "/source",
        "--emcc",
        "/compiler",
      ]),
    ).toThrow("explicit --pcre2 gate");
  });

  it("parses the exact staged-build contract", () => {
    expect(
      parsePcre2BuildArguments([
        "--pcre2",
        "--source-dir",
        "/source",
        "--emcc",
        "/compiler",
        "--force",
      ]),
    ).toEqual({
      mode: "pcre2",
      sourceDirectory: "/source",
      emccFile: "/compiler",
      force: true,
    });
  });

  it.each([
    ["--unknown"],
    ["--pcre2", "--pcre2"],
    ["--pcre2", "--source-dir"],
    ["--pcre2", "--force", "--force"],
  ])("rejects ambiguous arguments %j", (...arguments_) => {
    expect(() => parsePcre2BuildArguments(arguments_)).toThrow();
  });

  it("pins source, signed-tag object and compiler identities", () => {
    expect(PCRE2_LOCK.source.tag).toBe("pcre2-10.47");
    expect(PCRE2_LOCK.source.tagObject).toHaveLength(40);
    expect(PCRE2_LOCK.source.commit).toHaveLength(40);
    expect(PCRE2_LOCK.source.tree).toHaveLength(40);
    expect(PCRE2_LOCK.emscripten.version).toBe("6.0.4");
    expect(PCRE2_LOCK.emscripten.emccSha256).toHaveLength(64);
    expect(PCRE2_LOCK.bridgeAbi).toBe(3);
    expect(PCRE2_LOCK.maximumSubjectBytes).toBe(16 * 1024 * 1024);
    expect(PCRE2_LOCK.maximumMatches).toBe(10_000);
  });

  it("rejects an incomplete staged pack before attempting to load it", async () => {
    const directory = await mkdtemp(path.join(tmpdir(), "regex-pcre2-test-"));
    temporaryDirectories.push(directory);

    await expect(verifyPcre2Pack(directory, process.cwd())).rejects.toThrow(
      "must contain only",
    );
  });
});
