export type DeploymentRuntime = "bun" | "node" | "edge" | "worker" | "service-worker" | "browser";
export type RuntimeCapability =
  "filesystem" | "tcp" | "process" | "websocket" | "crypto" | "streams" | "background-tasks";

const CAPABILITIES: Record<DeploymentRuntime, ReadonlySet<RuntimeCapability>> = {
  bun: new Set([
    "filesystem",
    "tcp",
    "process",
    "websocket",
    "crypto",
    "streams",
    "background-tasks",
  ]),
  node: new Set([
    "filesystem",
    "tcp",
    "process",
    "websocket",
    "crypto",
    "streams",
    "background-tasks",
  ]),
  edge: new Set(["websocket", "crypto", "streams", "background-tasks"]),
  worker: new Set(["websocket", "crypto", "streams", "background-tasks"]),
  "service-worker": new Set(["crypto", "streams", "background-tasks"]),
  browser: new Set(["websocket", "crypto", "streams"]),
};

const MODULE_CAPABILITIES: Array<[RegExp, RuntimeCapability]> = [
  [/^(?:node:)?(?:fs|path|os)(?:\/|$)/, "filesystem"],
  [/^(?:node:)?(?:net|tls|dgram|http2)(?:\/|$)/, "tcp"],
  [/^(?:node:)?(?:child_process|cluster|worker_threads)(?:\/|$)/, "process"],
];

export interface RuntimeCapabilityDiagnostic {
  code: "WRN-RUNTIME-CAPABILITY";
  runtime: DeploymentRuntime;
  module: string;
  capability: RuntimeCapability;
  message: string;
}

export function runtimeCapabilities(runtime: DeploymentRuntime): ReadonlySet<RuntimeCapability> {
  return CAPABILITIES[runtime];
}

export function analyzeRuntimeImports(
  source: string,
  runtime: DeploymentRuntime,
): RuntimeCapabilityDiagnostic[] {
  const modules = [
    ...source.matchAll(/\b(?:import\s+(?:[\s\S]*?\s+from\s+)?|require\s*\()\s*["']([^"']+)["']/g),
  ].map((match) => match[1]!);
  const available = runtimeCapabilities(runtime);
  return modules.flatMap((module) => {
    const requirement = MODULE_CAPABILITIES.find(([pattern]) => pattern.test(module));
    if (!requirement || available.has(requirement[1])) return [];
    return [
      {
        code: "WRN-RUNTIME-CAPABILITY" as const,
        runtime,
        module,
        capability: requirement[1],
        message: `Module '${module}' requires ${requirement[1]}, which is unavailable in the ${runtime} runtime.`,
      },
    ];
  });
}
