import { spawn } from "node:child_process";

export interface BuildOpts {
  contextDir: string;
  dockerfile?: string;
  imageTag: string;
  onLine?: (line: string) => void;
}

export function buildAndPush(
  opts: BuildOpts,
): Promise<{ ok: boolean; tag: string; logTail: string }> {
  return new Promise((resolve) => {
    const args = [
      "build",
      "-t",
      opts.imageTag,
      "-f",
      opts.dockerfile ?? "Dockerfile",
      opts.contextDir,
    ];
    const proc = spawn("docker", args, {
      env: { ...process.env, DOCKER_BUILDKIT: "1" },
    });
    const buf: string[] = [];
    const sink = (chunk: Buffer) => {
      const s = chunk.toString();
      buf.push(s);
      if (opts.onLine) s.split("\n").forEach((l) => l && opts.onLine!(l));
    };
    proc.stdout.on("data", sink);
    proc.stderr.on("data", sink);
    proc.on("close", (code) => {
      if (code !== 0) {
        return resolve({
          ok: false,
          tag: opts.imageTag,
          logTail: buf.join("").slice(-65536),
        });
      }
      const push = spawn("docker", ["push", opts.imageTag]);
      push.stdout.on("data", sink);
      push.stderr.on("data", sink);
      push.on("close", (pcode) => {
        resolve({
          ok: pcode === 0,
          tag: opts.imageTag,
          logTail: buf.join("").slice(-65536),
        });
      });
    });
  });
}
