#!/usr/bin/env node
import { createHash } from "node:crypto";
import { spawnSync } from "node:child_process";
import {
  cp,
  lstat,
  mkdir,
  mkdtemp,
  readFile,
  rm,
  writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";

const scriptDir = dirname(fileURLToPath(import.meta.url));
const platformRoot = resolve(scriptDir, "../..");
const sourceRoot = resolve(platformRoot, "device-plane");
const artifactDir = resolve(
  process.env.NODEDC_DEPLOY_ARTIFACT_DIR
    || resolve(scriptDir, "../deploy-artifacts"),
);
const [patchId = "device-plane-postgres-bootstrap-20260725-001", ...extra] =
  process.argv.slice(2);

if (extra.length || !/^[A-Za-z0-9._-]{1,96}$/.test(patchId)) {
  throw new Error(
    "usage: build-device-plane-postgres-bootstrap-artifact.mjs [patch-id]",
  );
}

const files = [
  "docker-compose.device-plane.yml",
  "deployment/device-postgres-bootstrap-v1.json",
];
const stage = await mkdtemp(
  join(tmpdir(), "nodedc-device-plane-postgres-bootstrap-"),
);
const payload = join(stage, "payload");
const target = join(
  artifactDir,
  `nodedc-device-plane-${patchId}.tgz`,
);

await assertSourceBoundary();

try {
  await mkdir(payload, { recursive: true });
  for (const relativePath of files) {
    const source = resolve(sourceRoot, relativePath);
    const sourceStat = await lstat(source);
    if (!sourceStat.isFile() || sourceStat.isSymbolicLink()) {
      throw new Error(`bootstrap_source_file_required:${relativePath}`);
    }
    const destination = join(payload, relativePath);
    await mkdir(dirname(destination), { recursive: true });
    await cp(source, destination, {
      force: true,
      verbatimSymlinks: false,
    });
  }
  await writeFile(
    join(stage, "manifest.env"),
    `id=${patchId}\ncomponent=device-plane\ntype=app-overlay\n`,
    "utf8",
  );
  await writeFile(join(stage, "files.txt"), `${files.join("\n")}\n`, "utf8");
  await mkdir(artifactDir, { recursive: true });

  const tar = spawnSync(
    "python3",
    ["-c", canonicalTarScript(), target, stage],
    {
      encoding: "utf8",
      maxBuffer: 128 * 1024 * 1024,
    },
  );
  if (tar.status !== 0) {
    throw new Error(`tar_failed:${tar.stderr || tar.stdout}`);
  }

  const sha256 = createHash("sha256")
    .update(await readFile(target))
    .digest("hex");
  console.log(JSON.stringify({
    ok: true,
    patchId,
    artifact: target,
    sha256,
    component: "device-plane",
    entries: files,
    services: ["device-postgres"],
    mode: "create-if-absent",
    rollbackVolumePolicy: "preserve",
  }, null, 2));
} finally {
  await rm(stage, { recursive: true, force: true });
}

async function assertSourceBoundary() {
  const descriptor = JSON.parse(
    await readFile(
      resolve(
        sourceRoot,
        "deployment/device-postgres-bootstrap-v1.json",
      ),
      "utf8",
    ),
  );
  const expected = {
    schemaVersion: "nodedc.device-plane.postgres-bootstrap.v1",
    service: "device-postgres",
    volume: "nodedc-device-plane-postgres-data",
    mode: "create-if-absent",
    ordinaryApplicationSelection: "forbidden",
    rollbackVolumePolicy: "preserve",
  };
  if (JSON.stringify(descriptor) !== JSON.stringify(expected)) {
    throw new Error("device_plane_postgres_bootstrap_descriptor_mismatch");
  }

  const compose = await readFile(
    resolve(sourceRoot, "docker-compose.device-plane.yml"),
    "utf8",
  );
  for (const required of [
    "device-postgres:",
    "name: nodedc-device-plane-postgres-data",
    "POSTGRES_PASSWORD_FILE: /run/nodedc-secrets/postgres-password",
    "create_host_path: false",
  ]) {
    if (!compose.includes(required)) {
      throw new Error(`device_plane_postgres_boundary_missing:${required}`);
    }
  }
  const postgresStart = compose.indexOf("  device-postgres:");
  const postgresEnd = compose.indexOf("\n  device-control-core:");
  if (
    postgresStart < 0
    || postgresEnd <= postgresStart
    || compose.slice(postgresStart, postgresEnd).includes("\n    ports:")
  ) {
    throw new Error("device_plane_postgres_host_port_forbidden");
  }
}

function canonicalTarScript() {
  return [
    "import gzip,io,pathlib,sys,tarfile",
    "root=pathlib.Path(sys.argv[2])",
    "with open(sys.argv[1],'wb') as out:",
    " with gzip.GzipFile(filename='',mode='wb',fileobj=out,compresslevel=9,mtime=0) as gz:",
    "  with tarfile.open(fileobj=gz,mode='w',format=tarfile.PAX_FORMAT) as tar:",
    "   for top in ('manifest.env','files.txt','payload'):",
    "    p=root/top; paths=[p]+(sorted(p.rglob('*')) if p.is_dir() else [])",
    "    for x in paths:",
    "     info=tar.gettarinfo(str(x),arcname=x.relative_to(root).as_posix())",
    "     info.uid=info.gid=0; info.uname=info.gname='root'; info.mtime=0; info.mode=0o755 if info.isdir() else 0o644",
    "     with (open(x,'rb') if info.isfile() else io.BytesIO()) as src: tar.addfile(info,src if info.isfile() else None)",
  ].join("\n");
}
