import { spawnSync } from "node:child_process";

const input = JSON.parse(process.argv[2] || "{}");

function readPath(value, expression) {
  return String(expression || "")
    .replace(/^\$\.?/u, "")
    .split(".")
    .filter(Boolean)
    .reduce((current, key) => current == null ? undefined : current[key], value);
}

function responseCandidates(value) {
  return [value?.response?.response, value?.response, value].filter(Boolean);
}

function observationValue(value) {
  for (const candidate of responseCandidates(value)) {
    const observed = readPath(candidate, input.valuePath);
    if (observed !== undefined) return Number(observed);
  }
  return Number.NaN;
}

function sleep(milliseconds) {
  if (milliseconds > 0) Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
}

function boardCommand() {
  return [
    ...input.commandBase,
    "jrpctcp",
    "--host",
    input.host,
    "--port",
    String(input.port),
    ...(input.transport ? ["--transport", input.transport] : []),
    ...(input.targetNodeId ? ["--target-node-id", String(input.targetNodeId)] : []),
    input.method,
    input.path,
    ...input.params
  ];
}

sleep(input.settleMs);
const samples = [];
let response = null;
let exitCode = 0;

for (let index = 0; index < input.count; index += 1) {
  const command = boardCommand();
  const result = spawnSync(command[0], command.slice(1), { encoding: "utf8" });
  try {
    response = JSON.parse(String(result.stdout || "").trim());
  } catch {
    response = null;
  }
  const value = observationValue(response);
  if (Number.isFinite(value)) samples.push(value);
  if (result.status !== 0) exitCode = result.status || 1;
  if (index < input.count - 1) sleep(input.intervalMs);
}

const mean = samples.length > 0 ? samples.reduce((sum, value) => sum + value, 0) / samples.length : undefined;
const observation = {
  observationId: `obs_${input.probeId}_${Date.now()}`,
  probeId: input.probeId,
  quantity: input.quantity,
  unit: input.unit,
  samples,
  stats: samples.length > 0 ? { count: samples.length, mean, min: Math.min(...samples), max: Math.max(...samples) } : {},
  response,
  rawArtifactRef: response?.log_path || response?.logPath || response?.artifactRef || null
};

console.log(JSON.stringify(observation));
process.exit(exitCode === 0 && samples.length > 0 ? 0 : exitCode || 1);
