// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-25-p0-web-probe-sentinel.
// SPEC: PJ2026-01060508 Web哨兵 draft-2026-06-26-p9-multi-web-probe-sentinel.
// Responsibility: Redacted YAML configRef graph for web-probe sentinel plan/status.
import { readFileSync } from "node:fs";
import { rootPath } from "./config";
import { readWebProbeSentinelConfigRef } from "./hwlab-node-web-sentinel-config-ref";
import { HWLAB_WEB_PROBE_SENTINEL_CONFIG_REF_KEYS, type HwlabRuntimeLaneSpec, type HwlabRuntimeWebProbeSentinelConfigRefKey } from "./hwlab-node-lanes";
import { effectiveWebProbeSentinelPublicExposure, resolveWebProbeSentinel, webProbeSentinelRegistryRows, type WebProbeSentinelRegistryRow } from "./hwlab-node-web-sentinel-resolver";
import type { RenderedCliResult } from "./output";

export type WebProbeSentinelConfigAction = "plan" | "status";

export interface WebProbeSentinelConfigPlan {
  readonly ok: boolean;
  readonly command: string;
  readonly status: "ready" | "blocked" | "disabled";
  readonly node: string;
  readonly lane: string;
  readonly rootPath: string;
  readonly sentinelId: string | null;
  readonly enabled: boolean;
  readonly sentinels: readonly WebProbeSentinelRegistryRow[];
  readonly refs: readonly WebProbeSentinelConfigRefStatus[];
  readonly conflicts: readonly string[];
  readonly next: Record<string, string>;
  readonly valuesRedacted: true;
}

export interface WebProbeSentinelConfigRefStatus {
  readonly key: HwlabRuntimeWebProbeSentinelConfigRefKey;
  readonly ref: string;
  readonly file: string;
  readonly path: string;
  readonly present: boolean;
  readonly targetPresent: boolean;
  readonly targetKind: "object" | "array" | "scalar" | "null" | "missing";
  readonly sha256: string | null;
  readonly byteCount: number | null;
  readonly missingFields: readonly string[];
  readonly conflicts: readonly string[];
  readonly summary: string;
  readonly error: string | null;
}

interface InternalConfigRefStatus extends WebProbeSentinelConfigRefStatus {
  readonly target: unknown;
}

interface RequiredTargetShape {
  readonly kind: "object" | "array";
  readonly requiredPaths: readonly string[];
}

const REQUIRED_TARGET_SHAPES: Record<HwlabRuntimeWebProbeSentinelConfigRefKey, RequiredTargetShape> = {
  runtime: {
    kind: "object",
    requiredPaths: [
      "target.node",
      "target.lane",
      "target.publicOriginRef",
      "target.observeWrapperRef",
      "namespace",
      "serviceAccountName",
      "deploymentName",
      "serviceName",
      "listenHost",
      "servicePort",
      "pvcName",
      "pvcStorage",
      "stateRoot",
      "imageRef",
      "replicas",
      "healthPath",
      "metricsPath",
      "scheduler.intervalMs",
      "scheduler.heartbeatStaleSeconds",
      "scheduler.maxConcurrentRuns",
      "sqlite.path",
      "sqlite.busyTimeoutMs",
    ],
  },
  scenarios: {
    kind: "array",
    requiredPaths: [
      "id",
      "enabled",
      "cadence",
      "observeTargetPath",
      "sampleIntervalMs",
      "screenshotIntervalMs",
      "maxRunSeconds",
      "providerProfile",
      "providerProfileMode",
      "promptSetRef",
      "reportViewRef",
      "commandSequence[0].type",
    ],
  },
  promptSet: {
    kind: "object",
    requiredPaths: ["id", "providerProfile", "providerProfileMode", "promptSourceRef", "promptSourceKey", "promptCount", "redaction"],
  },
  reportViews: {
    kind: "object",
    requiredPaths: ["defaultView", "views[0]", "pageSize", "maxPageSize", "rawAccess", "checkCatalogRef", "detailMemory.maxPages", "detailMemory.maxSamplesPerPage", "redaction.prompt", "redaction.secrets"],
  },
  publicExposure: {
    kind: "object",
    requiredPaths: [
      "enabled",
      "mode",
      "publicBaseUrl",
      "hostname",
      "expectedA",
      "frpc.deploymentName",
      "frpc.image",
      "frpc.serverAddr",
      "frpc.serverPort",
      "frpc.tokenSourceRef",
      "frpc.tokenSourceKey",
      "frpc.secretName",
      "frpc.secretKey",
      "frpc.httpProxy.name",
      "frpc.httpProxy.localIP",
      "frpc.httpProxy.localPort",
      "caddy.route",
      "caddy.configPath",
      "caddy.serviceName",
      "caddy.managedBlockOwner",
    ],
  },
  cicd: {
    kind: "object",
    requiredPaths: [
      "controlPlaneConfigRef",
      "source.repository",
      "source.branch",
      "source.gitMirrorReadUrl",
      "source.buildContext",
      "source.entrypoint",
      "sourceAuthority.mode",
      "sourceAuthority.resolver",
      "sourceAuthority.allowHostGit",
      "sourceAuthority.allowGithubDirectInPipeline",
      "sourceSnapshot.stageRefPrefix",
      "sourceSnapshot.missingObjectPolicy",
      "sourceSnapshot.refreshPolicy",
      "sourceSnapshot.cacheRef",
      "gitopsPath",
      "argo.namespace",
      "argo.projectName",
      "argo.applicationName",
      "argo.repoURL",
      "argo.targetRevision",
      "image.repository",
      "image.tagSource",
      "image.baseImageRef",
      "image.envRecipeRef",
      "maintenance.startCommand",
      "maintenance.stopCommand",
      "confirmWait.maxSeconds",
      "targetValidation.scenarioId",
      "targetValidation.maxSeconds",
      "targetValidation.serviceUnavailablePolicy",
    ],
  },
  secrets: {
    kind: "object",
    requiredPaths: [
      "sources[0].purpose",
      "sources[0].sourceRef",
      "sources[0].sourceKey",
      "runtimeSecrets[0].name",
      "runtimeSecrets[0].namespace",
      "runtimeSecrets[0].data[0].sourcePurpose",
      "runtimeSecrets[0].data[0].targetKey",
    ],
  },
};

export function webProbeSentinelConfigPlan(spec: HwlabRuntimeLaneSpec, action: WebProbeSentinelConfigAction, sentinelId: string | null = null): WebProbeSentinelConfigPlan {
  const command = `web-probe sentinel ${action} --node ${spec.nodeId} --lane ${spec.lane}${sentinelId === null ? "" : ` --sentinel ${sentinelId}`}`;
  const registry = webProbeSentinelRegistryRows(spec);
  const registryPath = `config/hwlab-node-lanes.yaml#lanes.${spec.lane}.targets.${spec.nodeId}.observability.webProbe.sentinels`;
  if (sentinelId === null && registry.length > 1) {
    const enabled = registry.some((item) => item.enabled);
    return {
      ok: enabled,
      command,
      status: enabled ? "ready" : "disabled",
      node: spec.nodeId,
      lane: spec.lane,
      rootPath: registryPath,
      sentinelId: null,
      enabled,
      sentinels: registry,
      refs: [],
      conflicts: [],
      next: sentinelNext(spec.nodeId, spec.lane, registry[0]?.id ?? null),
      valuesRedacted: true,
    };
  }
  if (registry.length === 0) {
    return {
      ok: false,
      command,
      status: "blocked",
      node: spec.nodeId,
      lane: spec.lane,
      rootPath: registryPath,
      sentinelId,
      enabled: false,
      sentinels: [],
      refs: [],
      conflicts: [`${registryPath} is missing`],
      next: sentinelNext(spec.nodeId, spec.lane, sentinelId),
      valuesRedacted: true,
    };
  }

  const selected = resolveWebProbeSentinel(spec, sentinelId);
  const refs = HWLAB_WEB_PROBE_SENTINEL_CONFIG_REF_KEYS
    .map((key) => readSentinelConfigRef(spec, key, selected.configRefs[key]))
    .map((ref) => effectiveConfigRefStatus(spec, selected.id, ref));
  const conflicts = selected.enabled ? crossReferenceConflicts(spec, refs) : [];
  const refBlocked = refs.some((ref) => !ref.present || !ref.targetPresent || ref.missingFields.length > 0 || ref.conflicts.length > 0 || ref.error !== null);
  const ok = selected.enabled && !refBlocked && conflicts.length === 0;
  return {
    ok,
    command,
    status: selected.enabled ? ok ? "ready" : "blocked" : "disabled",
    node: spec.nodeId,
    lane: spec.lane,
    rootPath: selected.rootPath,
    sentinelId: selected.id,
    enabled: selected.enabled,
    sentinels: registry,
    refs: refs.map(stripInternalTarget),
    conflicts,
    next: sentinelNext(spec.nodeId, spec.lane, selected.id),
    valuesRedacted: true,
  };
}

function effectiveConfigRefStatus(spec: HwlabRuntimeLaneSpec, sentinelId: string, ref: InternalConfigRefStatus): InternalConfigRefStatus {
  if (ref.key !== "publicExposure" || !isRecord(ref.target)) return ref;
  const target = effectiveWebProbeSentinelPublicExposure(spec, sentinelId, ref.target);
  return {
    ...ref,
    targetKind: targetKindOf(target),
    missingFields: missingFieldsForTarget(ref.key, target),
    summary: summarizeTarget(ref.key, target),
    target,
  };
}

export function withWebProbeSentinelConfigRendered(value: WebProbeSentinelConfigPlan): RenderedCliResult {
  return {
    ok: value.ok,
    command: value.command,
    contentType: "text/plain",
    renderedText: renderWebProbeSentinelConfigPlan(value),
  };
}

function readSentinelConfigRef(spec: HwlabRuntimeLaneSpec, key: HwlabRuntimeWebProbeSentinelConfigRefKey, ref: string): InternalConfigRefStatus {
  try {
    const resolved = readWebProbeSentinelConfigRef(spec, ref);
    const target = resolved.target;
    const targetKind = target === undefined ? "missing" : targetKindOf(target);
    const missingFields = target === undefined ? ["target"] : missingFieldsForTarget(key, target);
    return {
      key,
      ref,
      file: resolved.file,
      path: resolved.path,
      present: true,
      targetPresent: target !== undefined,
      targetKind,
      sha256: resolved.sha256,
      byteCount: resolved.byteCount,
      missingFields,
      conflicts: [],
      summary: summarizeTarget(key, target),
      error: null,
      target,
    };
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    return emptyRefStatus(key, ref, "", "", message);
  }
}

function emptyRefStatus(key: HwlabRuntimeWebProbeSentinelConfigRefKey, ref: string, file: string, path: string, error: string): InternalConfigRefStatus {
  return {
    key,
    ref,
    file,
    path,
    present: false,
    targetPresent: false,
    targetKind: "missing",
    sha256: null,
    byteCount: null,
    missingFields: ["target"],
    conflicts: [],
    summary: "-",
    error,
    target: undefined,
  };
}

function missingFieldsForTarget(key: HwlabRuntimeWebProbeSentinelConfigRefKey, target: unknown): string[] {
  const shape = REQUIRED_TARGET_SHAPES[key];
  if (shape.kind === "array") {
    const items = key === "scenarios" && isRecord(target) ? [target] : Array.isArray(target) ? target : null;
    if (items === null) return [`expected ${shape.kind}`];
    if (items.length === 0) return ["[0]"];
    return items.flatMap((item, index) => shape.requiredPaths
      .filter((path) => valueAtPath(item, path) === undefined)
      .map((path) => `[${index}].${path}`));
  }
  if (!isRecord(target)) return [`expected ${shape.kind}`];
  return shape.requiredPaths.filter((path) => valueAtPath(target, path) === undefined);
}

function crossReferenceConflicts(spec: HwlabRuntimeLaneSpec, refs: readonly InternalConfigRefStatus[]): string[] {
  const byKey = new Map(refs.map((ref) => [ref.key, ref]));
  const conflicts: string[] = [];
  const runtime = recordTarget(byKey.get("runtime"));
  const scenarios = scenarioTargets(byKey.get("scenarios"));
  const promptSet = recordTarget(byKey.get("promptSet"));
  const reportViews = recordTarget(byKey.get("reportViews"));
  const cicd = recordTarget(byKey.get("cicd"));
  const secrets = recordTarget(byKey.get("secrets"));

  if (runtime !== null) {
    requireEquals(conflicts, byKey.get("runtime"), "target.node", spec.nodeId, `selected node ${spec.nodeId}`);
    requireEquals(conflicts, byKey.get("runtime"), "target.lane", spec.lane, `selected lane ${spec.lane}`);
    requireEquals(conflicts, byKey.get("runtime"), "namespace", spec.runtimeNamespace, `selected namespace ${spec.runtimeNamespace}`);
  }

  const scenarioIds = new Set<string>();
  const scenarioProviders = new Set<string>();
  for (const [index, scenario] of scenarios.entries()) {
    const id = stringAt(scenario, "id");
    if (id !== null) scenarioIds.add(id);
    const provider = stringAt(scenario, "providerProfile");
    if (provider !== null) scenarioProviders.add(provider);
    requireReadableConfigRef(spec, conflicts, byKey.get("scenarios"), `[${index}].promptSetRef`, scenario.promptSetRef);
    requireReadableConfigRef(spec, conflicts, byKey.get("scenarios"), `[${index}].reportViewRef`, scenario.reportViewRef);
  }

  const promptProvider = promptSet === null ? null : stringAt(promptSet, "providerProfile");
  if (promptProvider !== null && scenarioProviders.size > 0 && !scenarioProviders.has(promptProvider)) {
    conflicts.push(`${byKey.get("promptSet")?.file}#${byKey.get("promptSet")?.path}.providerProfile=${promptProvider} does not match scenario providerProfile set ${Array.from(scenarioProviders).join(",")}`);
  }

  const validationScenarioId = cicd === null ? null : stringAt(cicd, "targetValidation.scenarioId");
  if (validationScenarioId !== null && !scenarioIds.has(validationScenarioId)) {
    conflicts.push(`${byKey.get("cicd")?.file}#${byKey.get("cicd")?.path}.targetValidation.scenarioId=${validationScenarioId} is not declared in scenarios`);
  }

  validateReportViewsCheckCatalog(spec, conflicts, byKey.get("reportViews"), reportViews);

  const runtimeNamespace = runtime === null ? null : stringAt(runtime, "namespace");
  const runtimeSecrets = secrets === null ? [] : arrayAt(secrets, "runtimeSecrets");
  if (runtimeNamespace !== null) {
    for (const [index, item] of runtimeSecrets.entries()) {
      const namespace = stringAt(item, "namespace");
      if (namespace !== null && namespace !== runtimeNamespace) {
        conflicts.push(`${byKey.get("secrets")?.file}#${byKey.get("secrets")?.path}.runtimeSecrets[${index}].namespace=${namespace} does not match runtime namespace ${runtimeNamespace}`);
      }
    }
  }
  return conflicts;
}

function validateReportViewsCheckCatalog(spec: HwlabRuntimeLaneSpec, conflicts: string[], ref: InternalConfigRefStatus | undefined, reportViews: Record<string, unknown> | null): void {
  if (reportViews === null) return;
  const catalogRef = stringAt(reportViews, "checkCatalogRef");
  if (catalogRef === null) {
    conflicts.push(`${ref?.file ?? "-"}#${ref?.path ?? "-"}.checkCatalogRef is required`);
    return;
  }
  let catalog: Record<string, unknown>;
  try {
    const target = readWebProbeSentinelConfigRef(spec, catalogRef).target;
    catalog = isRecord(target) ? target : {};
  } catch (error) {
    conflicts.push(`${ref?.file ?? "-"}#${ref?.path ?? "-"}.checkCatalogRef=${catalogRef} is not readable: ${error instanceof Error ? error.message : String(error)}`);
    return;
  }
  const items = arrayAt(catalog, "items");
  if (items.length === 0) {
    conflicts.push(`${catalogRef}.items is empty`);
    return;
  }
  const byId = new Map<string, Record<string, unknown>>();
  const codes = new Set<string>();
  for (const [index, item] of items.entries()) {
    const itemId = stringAt(item, "id");
    const code = stringAt(item, "code");
    if (itemId === null) conflicts.push(`${catalogRef}.items[${index}].id is required`);
    else if (byId.has(itemId)) conflicts.push(`${catalogRef}.items id duplicated: ${itemId}`);
    else byId.set(itemId, item);
    if (code === null) conflicts.push(`${catalogRef}.items[${index}].code is required`);
    else if (codes.has(code)) conflicts.push(`${catalogRef}.items code duplicated: ${code}`);
    else codes.add(code);
    for (const field of ["titleZh", "summaryZh", "actionZh"]) {
      const text = stringAt(item, field);
      if (text === null) {
        conflicts.push(`${catalogRef}.items[${index}].${field} is required`);
      } else if (!containsChinese(text)) {
        conflicts.push(`${catalogRef}.items[${index}].${field} must contain Chinese text`);
      }
    }
  }
  const requiredIds = knownWebProbeFindingIds();
  const missing = requiredIds.filter((id) => !byId.has(id));
  if (missing.length > 0) {
    conflicts.push(`${catalogRef}.items missing analyzer finding ids: ${missing.slice(0, 24).join(",")}${missing.length > 24 ? `,+${missing.length - 24}` : ""}`);
  }
}

function knownWebProbeFindingIds(): string[] {
  const ids = new Set<string>();
  for (const file of [
    "scripts/src/hwlab-node-web-observe-analyzer-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-api-dom-lag-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-browser-process-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-findings-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-io-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-performance-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-project-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-request-runtime-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-sample-metrics-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-session-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-window-page-source.ts",
    "scripts/src/hwlab-node-web-observe-analyzer-workbench-triad-source.ts",
    "scripts/src/hwlab-node-web-sentinel-p5-observe.ts",
    "scripts/src/hwlab-node-web-sentinel-p5-observe-analysis.ts",
  ]) {
    let source = "";
    try {
      source = readFileSync(rootPath(file), "utf8");
    } catch {
      continue;
    }
    for (const match of source.matchAll(/\bid:\s*["`]([A-Za-z0-9_.:-]+)["`]/gu)) ids.add(match[1]);
  }
  return Array.from(ids).sort();
}

function containsChinese(value: string): boolean {
  return /[\u3400-\u9fff]/u.test(value);
}

function requireReadableConfigRef(spec: HwlabRuntimeLaneSpec, conflicts: string[], ref: InternalConfigRefStatus | undefined, path: string, value: unknown): void {
  if (typeof value !== "string" || value.length === 0) return;
  try {
    readWebProbeSentinelConfigRef(spec, value);
  } catch (error) {
    conflicts.push(`${ref?.file ?? "-"}#${ref?.path ?? "-"}.${path}=${value} is not readable: ${error instanceof Error ? error.message : String(error)}`);
  }
}

function requireEquals(conflicts: string[], ref: InternalConfigRefStatus | undefined, path: string, expected: string, expectedLabel: string): void {
  if (ref === undefined) return;
  const actual = stringAt(ref.target, path);
  if (actual !== null && actual !== expected) {
    conflicts.push(`${ref.file}#${ref.path}.${path}=${actual} does not match ${expectedLabel}`);
  }
}

function stripInternalTarget(ref: InternalConfigRefStatus): WebProbeSentinelConfigRefStatus {
  return {
    key: ref.key,
    ref: ref.ref,
    file: ref.file,
    path: ref.path,
    present: ref.present,
    targetPresent: ref.targetPresent,
    targetKind: ref.targetKind,
    sha256: ref.sha256,
    byteCount: ref.byteCount,
    missingFields: ref.missingFields,
    conflicts: ref.conflicts,
    summary: ref.summary,
    error: ref.error,
  };
}

function summarizeTarget(key: HwlabRuntimeWebProbeSentinelConfigRefKey, target: unknown): string {
  if (target === undefined) return "target=missing";
  if (key === "scenarios") {
    const items = isRecord(target) ? [target] : Array.isArray(target) ? target : [];
    const ids = items.map((item) => stringAt(item, "id")).filter((item): item is string => item !== null).slice(0, 4);
    const cadences = items.map((item) => stringAt(item, "cadence")).filter((item): item is string => item !== null).slice(0, 4);
    const checks = items.flatMap((item) => arrayAt(item, "sessionInvarianceChecks"));
    const afterRounds = checks
      .map((item) => {
        const value = isRecord(item) ? item.afterRound : null;
        return typeof value === "number" ? String(value) : null;
      })
      .filter((item): item is string => item !== null)
      .slice(0, 8);
    return `items=${items.length} ids=${ids.join(",") || "-"} cadence=${cadences.join(",") || "-"} sessionInvarianceChecks=${checks.length} afterRound=${afterRounds.join(",") || "-"}`;
  }
  if (!isRecord(target)) return `kind=${targetKindOf(target)}`;
  if (key === "runtime") return `namespace=${textAt(target, "namespace")} service=${textAt(target, "serviceName")} image=${short(textAt(target, "imageRef"), 48)}`;
  if (key === "promptSet") return `id=${textAt(target, "id")} provider=${textAt(target, "providerProfile")} prompts=${textAt(target, "promptCount")} markers=${arrayAt(target, "expectedMarkers").slice(0, 12).join(",") || "-"} source=${textAt(target, "promptSourceRef")}:${textAt(target, "promptSourceKey")}`;
  if (key === "reportViews") return `default=${textAt(target, "defaultView")} views=${arrayAt(target, "views").length}`;
  if (key === "publicExposure") {
    const monitorRoot = textAt(target, "monitorRoot.enabled");
    const rootOrder = textAt(target, "caddy.rootOrder");
    const suffix = [
      ...(monitorRoot === "-" ? [] : [`monitorRoot=${monitorRoot}`]),
      ...(rootOrder === "-" ? [] : [`rootOrder=${rootOrder}`]),
    ].join(" ");
    return `enabled=${textAt(target, "enabled")} mode=${textAt(target, "mode")} url=${textAt(target, "publicBaseUrl")}${suffix.length === 0 ? "" : ` ${suffix}`}`;
  }
  if (key === "cicd") return `gitops=${textAt(target, "gitopsPath")} image=${textAt(target, "image.repository")}:${textAt(target, "image.tagSource")} confirmWait=${textAt(target, "confirmWait.maxSeconds")} targetValidation=${textAt(target, "targetValidation.maxSeconds")}`;
  if (key === "secrets") return `sources=${arrayAt(target, "sources").length} runtimeSecrets=${arrayAt(target, "runtimeSecrets").length}`;
  return `keys=${Object.keys(target).length}`;
}

function renderWebProbeSentinelConfigPlan(value: WebProbeSentinelConfigPlan): string {
  const blocked = value.ok ? [] : [
    "",
    "Blocked detail:",
    sentinelTable(["KIND", "VALUE"], [
      ...value.conflicts.map((item) => ["conflict", item]),
      ...value.refs.flatMap((ref) => [
        ...(ref.error === null ? [] : [[`${ref.key}.error`, ref.error]]),
        ...(ref.missingFields.length === 0 ? [] : [[`${ref.key}.missing`, ref.missingFields.join(",")]]),
        ...(ref.conflicts.length === 0 ? [] : [[`${ref.key}.conflict`, ref.conflicts.join(" | ")]]),
      ]),
    ]),
  ];
  return [
    `web-probe sentinel ${commandAction(value.command)} (${value.status})`,
    "",
    sentinelTable(["NODE", "LANE", "SENTINEL", "ENABLED", "OK", "ROOT"], [[value.node, value.lane, value.sentinelId ?? "registry", value.enabled, value.ok, value.rootPath]]),
    ...(value.sentinels.length === 0 ? [] : [
      "",
      sentinelTable(
        ["SENTINEL", "ENABLED", "ROOT", "CONFIG_REF"],
        value.sentinels.map((item) => [item.id, item.enabled, item.monitorRoot ? "monitor-root" : "-", short(item.configRef, 110)]),
      ),
    ]),
    ...(value.refs.length === 0 ? [
      "",
      "DRILL_DOWN",
      ...value.sentinels.map((item) => `  ${item.id}: bun scripts/cli.ts web-probe sentinel ${commandAction(value.command)} --node ${value.node} --lane ${value.lane} --sentinel ${item.id}`),
    ] : [
    "",
    sentinelTable(
      ["KEY", "PRESENT", "TARGET", "TYPE", "HASH", "MISSING", "SUMMARY"],
      value.refs.map((ref) => [
        ref.key,
        ref.present,
        ref.targetPresent,
        ref.targetKind,
        ref.sha256 === null ? "-" : `${ref.sha256.slice(0, 19)}...`,
        ref.missingFields.length === 0 ? "-" : short(ref.missingFields.join(","), 52),
        short(ref.summary, 90),
      ]),
    ),
    "",
    sentinelTable(
      ["KEY", "FILE", "PATH", "BYTES"],
      value.refs.map((ref) => [ref.key, ref.file, ref.path, ref.byteCount ?? "-"]),
    ),
    ]),
    ...blocked,
    "",
    "NEXT",
    `  plan: ${value.next.plan}`,
    `  status: ${value.next.status}`,
    "DISCLOSURE",
    "  valuesRedacted=true; secret values and full YAML objects are not printed.",
  ].join("\n");
}

function sentinelNext(node: string, lane: string, sentinelId: string | null): Record<string, string> {
  const suffix = sentinelId === null ? "" : ` --sentinel ${sentinelId}`;
  return {
    plan: `bun scripts/cli.ts web-probe sentinel plan --node ${node} --lane ${lane}${suffix} --dry-run`,
    status: `bun scripts/cli.ts web-probe sentinel status --node ${node} --lane ${lane}${suffix}`,
  };
}

function valueAtPath(value: unknown, path: string): unknown {
  let current: unknown = value;
  for (const segment of path.split(".")) {
    if (segment.length === 0) return undefined;
    const match = /^(?:([A-Za-z0-9_-]+))?(?:\[(\d+)\])?$/u.exec(segment);
    if (match === null) return undefined;
    if (match[1] !== undefined) {
      if (!isRecord(current)) return undefined;
      current = current[match[1]];
    }
    if (match[2] !== undefined) {
      if (!Array.isArray(current)) return undefined;
      current = current[Number(match[2])];
    }
  }
  return current;
}

function stringAt(value: unknown, path: string): string | null {
  const found = valueAtPath(value, path);
  return typeof found === "string" && found.length > 0 ? found : null;
}

function textAt(value: unknown, path: string): string {
  const found = valueAtPath(value, path);
  if (typeof found === "string") return found;
  if (typeof found === "number" || typeof found === "boolean") return String(found);
  return "-";
}

function arrayAt(value: unknown, path: string): unknown[] {
  const found = valueAtPath(value, path);
  return Array.isArray(found) ? found : [];
}

function recordTarget(ref: InternalConfigRefStatus | undefined): Record<string, unknown> | null {
  return ref !== undefined && isRecord(ref.target) ? ref.target : null;
}

function arrayTarget(ref: InternalConfigRefStatus | undefined): Record<string, unknown>[] {
  return ref !== undefined && Array.isArray(ref.target) ? ref.target.filter(isRecord) : [];
}

function scenarioTargets(ref: InternalConfigRefStatus | undefined): Record<string, unknown>[] {
  if (ref === undefined) return [];
  if (Array.isArray(ref.target)) return ref.target.filter(isRecord);
  return isRecord(ref.target) ? [ref.target] : [];
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function targetKindOf(value: unknown): "object" | "array" | "scalar" | "null" {
  if (value === null) return "null";
  if (Array.isArray(value)) return "array";
  if (isRecord(value)) return "object";
  return "scalar";
}

function commandAction(command: string): string {
  return command.includes(" status ") ? "status" : "plan";
}

function sentinelTable(headers: string[], rows: unknown[][]): string {
  const normalized = [headers, ...rows.map((row) => row.map((cell) => sentinelText(cell)))];
  const widths = headers.map((_, index) => Math.max(...normalized.map((row) => sentinelText(row[index] ?? "").length)));
  return normalized.map((row) => row.map((cell, index) => sentinelText(cell).padEnd(widths[index])).join("  ").trimEnd()).join("\n");
}

function sentinelText(value: unknown): string {
  if (value === null || value === undefined || value === "") return "-";
  if (typeof value === "boolean") return value ? "true" : "false";
  return String(value).replace(/\s+/gu, " ").trim();
}

function short(value: string, maxLength: number): string {
  if (value.length <= maxLength) return value;
  if (maxLength <= 1) return value.slice(0, maxLength);
  return `${value.slice(0, maxLength - 1)}~`;
}
