import fs from "fs";
import os from "os";
import path from "path";
import { pathToFileURL } from "url";
import { afterEach, describe, expect, it } from "vitest";
import { bundleK6File } from "./index.mjs";

const cleanups = [];

afterEach(() => {
  while (cleanups.length > 0) {
    cleanups.pop()();
  }
});

describe("runtime bundler", () => {
  it("bundles root and runtime package imports for execution", async () => {
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
    cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));

    const sourceFile = path.join(tmpDir, "health.js");
    fs.writeFileSync(
      sourceFile,
      [
        'import { defineHttpSuite } from "@elench/testkit";',
        'import { check, json } from "@elench/testkit/runtime";',
        "const suite = defineHttpSuite(({ rawReq }) => {",
        '  const res = rawReq("GET", "/health");',
        "  check(json(res), {",
        '    "has status": (body) => typeof body.status === "string",',
        "  });",
        "});",
        "export default suite;",
        "",
      ].join("\n")
    );

    const bundledFile = await bundleK6File({
      productDir: tmpDir,
      serviceName: "api",
      sourceFile,
    });

    const bundled = fs.readFileSync(bundledFile, "utf8");
    expect(bundled).toContain("defineHttpSuite");
    expect(bundled).toContain('import { check');
    expect(bundled).toContain('from "k6"');
  });

  it("bundles DAL execution through the public package surface", async () => {
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
    cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));

    const sourceFile = path.join(tmpDir, "dal.js");
    fs.writeFileSync(
      sourceFile,
      [
        'import { defineDalSuite } from "@elench/testkit";',
        "const suite = defineDalSuite(({ db }) => {",
        '  db.query("SELECT 1");',
        "});",
        "export default suite;",
        "",
      ].join("\n")
    );

    const bundledFile = await bundleK6File({
      productDir: tmpDir,
      serviceName: "api",
      sourceFile,
    });

    const bundled = fs.readFileSync(bundledFile, "utf8");
    expect(bundled).toContain("defineDalSuite");
    expect(bundled).toContain('import sql from "k6/x/sql"');
  });

  it("normalizes a default-exported suite object with no setup override", async () => {
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
    cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));

    const sourceFile = path.join(tmpDir, "no-setup.js");
    fs.writeFileSync(
      sourceFile,
      [
        "const suite = {",
        "  options: { vus: 1, iterations: 1 },",
        "  exec() {",
        "    return 'ok';",
        "  },",
        "};",
        "export default suite;",
        "",
      ].join("\n")
    );

    const bundledFile = await bundleK6File({
      productDir: tmpDir,
      serviceName: "api",
      sourceFile,
    });

    const bundled = await import(`${pathToFileURL(bundledFile).href}?v=${Date.now()}`);
    expect(typeof bundled.setup).toBe("function");
    expect(bundled.setup()).toBeNull();
    expect(typeof bundled.default).toBe("function");
    expect(bundled.default()).toBe("ok");
  });

  it("throws a clear error when the default export is not a suite object", async () => {
    const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
    cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));

    const sourceFile = path.join(tmpDir, "legacy-shape.js");
    fs.writeFileSync(
      sourceFile,
      [
        "export default function exec() {",
        "  return 'legacy';",
        "}",
        "",
      ].join("\n")
    );

    const bundledFile = await bundleK6File({
      productDir: tmpDir,
      serviceName: "api",
      sourceFile,
    });

    await expect(
      import(`${pathToFileURL(bundledFile).href}?v=${Date.now()}`)
    ).rejects.toThrow(/default-export the suite object/);
  });
});
