// Buildbox disk admission at the 15 GiB red floor. Shared by run-remote and tests.
import { execFileSync } from "node:child_process";
import { statSync } from "node:fs";
import { dirname, resolve } from "node:path";

export const RED_FLOOR_BYTES = 15 * 1024 ** 3;

export function atLeastRedFloor(value) {
  const parsed = Number.parseInt(String(value), 10);
  if (!Number.isFinite(parsed)) return RED_FLOOR_BYTES;
  return Math.max(parsed, RED_FLOOR_BYTES);
}

export function resolveFloorBytes(env = process.env) {
  const rawBytes = env.BUILDBOX_DISK_MIN_FREE_BYTES;
  if (rawBytes != null && rawBytes !== "") {
    const parsed = Number.parseInt(String(rawBytes), 10);
    if (Number.isFinite(parsed)) return atLeastRedFloor(parsed);
  }
  const rawGib = env.BUILDBOX_DISK_MIN_FREE_GIB;
  if (rawGib != null && rawGib !== "") {
    const parsed = Number.parseInt(String(rawGib), 10);
    if (Number.isFinite(parsed)) return atLeastRedFloor(parsed * 1024 ** 3);
  }
  return RED_FLOOR_BYTES;
}

export function resolveProbePath(destination) {
  let path = resolve(destination);
  try {
    statSync(path);
    return path;
  } catch {
    let parent = dirname(path);
    while (true) {
      try {
        statSync(parent);
        return resolve(parent);
      } catch {
        if (parent === dirname(parent)) return null;
        parent = dirname(parent);
      }
    }
  }
}

export function uniqueFilesystemProbePaths(destinations) {
  const seen = new Map();
  for (const destination of destinations) {
    const probe = resolveProbePath(destination);
    if (!probe) return { paths: [], known: false };
    try {
      const dev = statSync(probe).dev;
      if (!seen.has(dev)) seen.set(dev, probe);
    } catch {
      return { paths: [], known: false };
    }
  }
  return { paths: [...seen.values()], known: true };
}

export function diskFreeBytes(target, deps = {}) {
  const execFile = deps.execFileSync || execFileSync;
  try {
    const out = String(execFile("df", ["-B1", "--output=avail", target], { encoding: "utf8" }));
    const line = out.trim().split("\n").pop() || "";
    const avail = Number.parseInt(line.replace(/\D/g, ""), 10);
    return Number.isFinite(avail) ? avail : null;
  } catch {
    return null;
  }
}

export function admitNewWork({ destinations, floorBytes, freeBytesFn, env } = {}) {
  const floor = floorBytes == null ? resolveFloorBytes(env) : atLeastRedFloor(floorBytes);
  const probe = freeBytesFn || diskFreeBytes;
  const { paths, known } = uniqueFilesystemProbePaths(destinations);
  if (!known) {
    return { admit: false, freeBytes: null, reason: "unknown", floorBytes: floor, paths: [] };
  }
  let minimum = null;
  for (const path of paths) {
    const free = probe(path);
    if (free == null) {
      return { admit: false, freeBytes: null, reason: "unknown", floorBytes: floor, paths };
    }
    minimum = minimum == null ? free : Math.min(minimum, free);
    if (free < floor) {
      return { admit: false, freeBytes: free, reason: "below-floor", floorBytes: floor, paths, failingMount: path };
    }
  }
  return { admit: true, freeBytes: minimum, reason: "ok", floorBytes: floor, paths };
}

export function formatCapacityRefusal({ host, verdict }) {
  const required = verdict.floorBytes ?? RED_FLOOR_BYTES;
  if (verdict.reason === "unknown") {
    const mount = verdict.failingMount || (verdict.paths?.[0] ?? "unknown");
    return `run-remote: disk admission refused on ${host}: mount=${mount} free=unknown required=${required} bytes`;
  }
  const mount = verdict.failingMount || (verdict.paths?.find(() => true) ?? "unknown");
  return `run-remote: disk admission refused on ${host}: mount=${mount} free=${verdict.freeBytes} bytes required=${required} bytes`;
}

export function buildRemoteDiskAdmissionScript(destinations) {
  const quoted = destinations.map((d) => `'${String(d).replace(/'/g, `'\\''`)}'`).join(" ");
  return [
    "set -euo pipefail",
    ". /usr/local/lib/buildbox/disk-admission.sh",
    `buildbox_disk_admit "$(hostname -s 2>/dev/null || hostname)" ${quoted}`,
  ].join("\n");
}
