// @vitest-environment node

import { cp, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { verifyPythonPack } from "./python-engine-pack.mjs";
import {
  PYTHON_LEGAL_RESOURCES,
  PYTHON_SOURCE_MANIFEST_BASE,
} from "./python-engine-provenance.mjs";

const temporaryDirectories: string[] = [];

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

describe("Python engine-pack provenance gate", () => {
  it("pins the complete base-runtime source, patch, and legal closure", () => {
    expect(PYTHON_LEGAL_RESOURCES.map(({ output }) => output)).toEqual([
      "LICENSE.pyodide.txt",
      "LICENSE.pyodide-stacktrace-vendors.txt",
      "LICENSE.cpython.txt",
      "NOTICE.cpython-bundled.rst",
      "LICENSE.expat.txt",
      "LICENSE.libmpdec.txt",
      "LICENSE.hacl-mit.txt",
      "LICENSE.libffi.txt",
      "LICENSE.hiwire.txt",
      "LICENSE.xz.txt",
      "LICENSE.zstd.txt",
      "LICENSE.sqlite.txt",
      "LICENSE.bzip2.txt",
      "LICENSE.zlib.txt",
      "LICENSE.emscripten.txt",
      "NOTICE.emscripten-dlmalloc.txt",
      "NOTICE.emscripten-musl.txt",
      "LICENSE.llvm-compiler-rt.txt",
      "LICENSE.llvm-libcxx.txt",
      "LICENSE.llvm-libcxxabi.txt",
      "LICENSE.llvm-libunwind.txt",
      "LICENSE.emscripten-mini-lz4.txt",
    ]);
    expect(PYTHON_SOURCE_MANIFEST_BASE.patches.cpython).toHaveLength(9);
    expect(PYTHON_SOURCE_MANIFEST_BASE.patches.emscripten).toHaveLength(5);
    expect(
      PYTHON_SOURCE_MANIFEST_BASE.sourceInputs.map(({ id }) => id),
    ).toEqual([
      "pyodide",
      "pyodide-build",
      "error-stack-parser",
      "stackframe",
      "cpython",
      "libffi",
      "hiwire",
      "xz-liblzma",
      "zstandard",
      "sqlite",
      "bzip2",
      "zlib",
      "emscripten",
      "hacl-star-preferred-source",
    ]);
  });

  it("verifies the installed runtime and independently anchored inventory", async () => {
    await expect(
      verifyPythonPack(
        path.resolve("public", "engines", "python"),
        path.resolve(),
      ),
    ).resolves.toEqual(
      expect.objectContaining({
        engineVersion: "CPython 3.14.2 re",
        runtime: "Pyodide 314.0.3",
        source: expect.objectContaining({
          manifest: expect.objectContaining({
            path: "SOURCE-MANIFEST.json",
          }),
        }),
      }),
    );
  }, 30_000);

  it("rejects substituted legal material before runtime startup", async () => {
    const directory = await mkdtemp(path.join(tmpdir(), "regex-python-pack-"));
    temporaryDirectories.push(directory);
    const pack = path.join(directory, "python");
    await cp(path.resolve("public", "engines", "python"), pack, {
      recursive: true,
    });
    await writeFile(
      path.join(pack, "LICENSE.libffi.txt"),
      "substituted legal text\n",
    );

    await expect(verifyPythonPack(pack, path.resolve())).rejects.toThrow(
      /libffi legal material SHA-256 mismatch/u,
    );
  });

  it("ships a manifest whose legal records match every pinned output", async () => {
    const manifest = JSON.parse(
      await readFile(
        path.resolve("public", "engines", "python", "SOURCE-MANIFEST.json"),
        "utf8",
      ),
    ) as {
      legalFiles: {
        path: string;
        sha256: string;
        sourceSha256: string;
      }[];
    };
    expect(
      manifest.legalFiles.map(({ path: file, sha256, sourceSha256 }) => ({
        file,
        sha256,
        sourceSha256,
      })),
    ).toEqual(
      PYTHON_LEGAL_RESOURCES.map(({ output, outputSha256, sourceSha256 }) => ({
        file: output,
        sha256: outputSha256,
        sourceSha256,
      })),
    );
  });
});
