// src/layer/ExecToolInjectLayer.ts
import type { Layer, SavingEvent } from "./types.ts";

const ALL_LANG_BINARIES: Record<string, string> = {
  python: "python3", javascript: "node", typescript: "bun",
  ruby: "ruby", php: "php", perl: "perl", r: "Rscript",
};

export class ExecToolInjectLayer implements Layer {
  readonly id = "exec-tool-inject";
  readonly available: string[];

  constructor() {
    // Bun.which() — no child_process; returns path string or null
    this.available = Object.entries(ALL_LANG_BINARIES)
      .filter(([, bin]) => Bun.which(bin) !== null)
      .map(([lang]) => lang);
  }

  init(): void {}

  outbound(body: unknown): unknown {
    if (!this.available.length) return body;
    if (typeof body !== "object" || body === null) return body;
    const b = body as Record<string, unknown>;
    if (!Array.isArray(b.tools)) return body;
    const tools = b.tools as unknown[];
    // Idempotent: don't double-inject
    if (tools.some(t => (t as Record<string, unknown>).name === "exec")) return body;
    return {
      ...b,
      tools: [...tools, {
        name: "exec",
        description: `Run code. Langs: ${this.available.join(",")}`,
        input_schema: {
          type: "object",
          properties: {
            code:     { type: "string" },
            language: { type: "string", enum: this.available },
          },
          required: ["code"],
        },
      }],
    };
  }

  inbound(body: unknown): unknown { return body; }
  observe(): SavingEvent[] { return []; }
  dispose(): void {}
}
