import { spawnSync } from "node:child_process";
import { homedir } from "node:os";
import { join } from "node:path";

const HOME = homedir();
const MUX_TEMPLATE = join(HOME, ".ssh", "rb-%r@%h-%p");

export function shq(value) { return `'${String(value).replace(/'/g, `'\\''`)}'`; }

export function sshOpts(cfg, { mux = true } = {}) {
  const opts = ["-F", "/dev/null", "-o", "BatchMode=yes", "-o", `ConnectTimeout=${cfg.connect_timeout_sec}`,
    ...(mux ? ["-o", "ControlMaster=auto", "-o", `ControlPath=${MUX_TEMPLATE}`, "-o", "ControlPersist=600"]
      : ["-o", "ControlMaster=no", "-o", "ControlPath=none"]),
    "-o", "ServerAliveInterval=15", "-o", "ServerAliveCountMax=4", "-o", "StrictHostKeyChecking=accept-new", "-p", String(cfg.port)];
  if (cfg.identity_file) opts.push("-o", "IdentitiesOnly=yes", "-i", cfg.identity_file.replace(/^~(?=\/)/, HOME));
  return opts;
}

export function sshTarget(cfg) { return `${cfg.ssh_user}@${cfg.host}`; }

export function probeMs(cfg, fallbackSec = 15) {
  return (cfg.ssh_probe_timeout_sec ?? fallbackSec) * 1000;
}

export function remoteTransport(cfg, command, opts = {}, deps = {}) {
  const spawn = deps.spawnSync ?? spawnSync;
  const timeout = opts.timeoutSec ? opts.timeoutSec * 1000 : probeMs(cfg);
  const { timeoutSec, input, maxBuffer, ...rest } = opts;
  const spawnOpts = { encoding: "utf8", timeout, ...rest };
  if (input !== undefined) spawnOpts.input = input;
  if (maxBuffer !== undefined) spawnOpts.maxBuffer = maxBuffer;
  return spawn("ssh", [...sshOpts(cfg), sshTarget(cfg), command], spawnOpts);
}

export function remoteTransportBashS(cfg, stdinPayload, opts = {}, deps = {}) {
  return remoteTransport(cfg, "bash -s", { ...opts, input: stdinPayload, maxBuffer: opts.maxBuffer ?? 64 * 1024 * 1024 }, deps);
}
