// @vitest-environment node
import { createHash } from "node:crypto";
import { mkdtemp, readFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import {
  buildRubyPack,
  RUBY_ENGINE_LOCK,
  verifyRubyPack,
} from "./ruby-engine-pack.mjs";

const temporaryDirectories: string[] = [];

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

async function digest(file: string): Promise<string> {
  return createHash("sha256")
    .update(await readFile(file))
    .digest("hex");
}

describe("Ruby engine-pack gate", () => {
  it("verifies the installed minimal CRuby runtime and native smoke cases", async () => {
    await expect(
      verifyRubyPack(path.resolve("public", "engines", "ruby")),
    ).resolves.toEqual(
      expect.objectContaining({
        engineVersion: "CRuby 4.0.0 Regexp",
        platform: "wasm32-wasi",
        source: expect.objectContaining({
          runtimeVariant: "minimal ruby.wasm (without bundled stdlib/debug)",
        }),
      }),
    );
  });

  it("pins exact runtime/host package and WebAssembly identities", () => {
    expect(RUBY_ENGINE_LOCK.packageVersion).toBe("2.9.3-2.9.4");
    expect(RUBY_ENGINE_LOCK.rubyVersion).toBe("4.0.0");
    expect(RUBY_ENGINE_LOCK.platform).toBe("wasm32-wasi");
    expect(RUBY_ENGINE_LOCK.npm.runtime.integrity).toMatch(/^sha512-/u);
    expect(RUBY_ENGINE_LOCK.npm.host.integrity).toMatch(/^sha512-/u);
    expect(RUBY_ENGINE_LOCK.sourceAssets["ruby.wasm"]).toHaveLength(64);
  });

  it("builds byte-identical closed packs from the pinned npm inputs", async () => {
    const directory = await mkdtemp(path.join(tmpdir(), "regex-ruby-pack-"));
    temporaryDirectories.push(directory);
    const first = path.join(directory, "first");
    const second = path.join(directory, "second");

    await buildRubyPack({ output: first });
    await buildRubyPack({ output: second });

    for (const file of [
      "ruby.wasm",
      "engine-metadata.json",
      "SHA256SUMS",
      "LICENSE.ruby-wasm.txt",
      "NOTICE.txt",
    ]) {
      expect(await digest(path.join(first, file))).toBe(
        await digest(path.join(second, file)),
      );
    }
  }, 30_000);
});
