import fs from "fs";
import os from "os";
import path from "path";
import crypto from "crypto";
import { build } from "esbuild";
import { fileURLToPath } from "url";

const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
const ROOT_ENTRY = path.join(PACKAGE_ROOT, "lib", "index.mjs");
const K6_ENTRY = path.join(PACKAGE_ROOT, "lib", "k6", "index.mjs");
const K6_DIR = path.join(PACKAGE_ROOT, "lib", "k6");
const bundleCache = new Map();

export async function bundleK6File({
  productDir,
  serviceName,
  sourceFile,
}) {
  const absoluteSource = path.resolve(productDir, sourceFile);
  const bundleDir = path.join(productDir, ".testkit", "_bundles", serviceName || "shared");
  fs.mkdirSync(bundleDir, { recursive: true });

  const cacheKey = await buildCacheKey(absoluteSource);
  const cached = bundleCache.get(cacheKey);
  if (cached && fs.existsSync(cached)) {
    return cached;
  }

  const outputFile = path.join(
    bundleDir,
    `${path.basename(sourceFile, path.extname(sourceFile))}-${cacheKey.slice(0, 12)}.js`
  );

  await build({
    absWorkingDir: path.dirname(absoluteSource),
    bundle: true,
    entryPoints: [absoluteSource],
    format: "esm",
    legalComments: "none",
    outfile: outputFile,
    platform: "neutral",
    sourcemap: "inline",
    target: "es2020",
    plugins: [testkitPackageAliasPlugin()],
    external: [
      "k6",
      "k6/*",
    ],
  });

  bundleCache.set(cacheKey, outputFile);
  return outputFile;
}

async function buildCacheKey(sourceFile) {
  const source = await fs.promises.readFile(sourceFile, "utf8");
  const packageJson = await fs.promises.readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8");
  return crypto
    .createHash("sha256")
    .update(sourceFile)
    .update("\0")
    .update(source)
    .update("\0")
    .update(packageJson)
    .digest("hex");
}

function testkitPackageAliasPlugin() {
  return {
    name: "testkit-package-alias",
    setup(buildApi) {
      buildApi.onResolve({ filter: /^@elench\/testkit(?:\/.*)?$/ }, (args) => {
        return {
          namespace: "file",
          path: resolvePackageSubpath(args.path),
        };
      });
    },
  };
}

function resolvePackageSubpath(specifier) {
  const subpath = specifier.slice("@elench/testkit".length);
  if (!subpath) return ROOT_ENTRY;
  if (subpath === "/k6") return K6_ENTRY;
  if (subpath.startsWith("/k6/")) {
    const rel = subpath.slice("/k6/".length);
    const candidate = path.join(K6_DIR, `${rel}.mjs`);
    if (fs.existsSync(candidate)) {
      return candidate;
    }
  }

  throw new Error(`Unsupported @elench/testkit import "${specifier}" in ${os.platform()}`);
}
