import { readFileSync } from "node:fs";
import type { UniDeskConfig } from "./config";
import { rootPath } from "./config";
import type { RenderedCliResult } from "./output";
import { renderMachine } from "./agentrun/render";
import { resolveAgentRunLaneTarget } from "./agentrun-lanes";
import {
  capture,
  compactCapture,
  createYamlFieldReader,
  parseJsonOutput,
  readYamlRecord,
  sha256Hex,
  shQuote,
} from "./platform-infra-ops-library";

const configFile = rootPath("config", "platform-infra", "kafka.yaml");
const configLabel = "config/platform-infra/kafka.yaml";
const fieldManager = "unidesk-platform-infra-kafka";
const y = createYamlFieldReader(configLabel);
const kafkaConsumerGroupsNativeScript = readFileSync(rootPath("scripts", "native", "platform-infra", "kafka-consumer-groups.py"), "utf8");
const kafkaConsumerGroupRetentionNativeScript = readFileSync(rootPath("scripts", "native", "platform-infra", "kafka-consumer-group-retention.sh"), "utf8");
const kafkaReplayDiagnosticsNativeScript = readFileSync(rootPath("scripts", "native", "platform-infra", "kafka-replay-diagnostics.py"), "utf8");

interface ResourceBudget {
  requests: { cpu: string; memory: string };
  limits: { cpu: string; memory: string };
}

interface JvmBudget {
  xms: string;
  xmx: string;
}

interface EntityOperatorBudget {
  resources: ResourceBudget;
  jvmOptions: JvmBudget;
}

interface KafkaTarget {
  id: string;
  route: string;
  namespace: string;
  role: "active" | "standby";
  enabled: boolean;
  createNamespace: boolean;
  storageClassName: string;
}

interface KafkaTopicSpec {
  name: string;
  partitions: number;
  replicas: number;
  retentionMs: number;
  cleanupPolicy: "delete" | "compact";
  description: string;
}

interface KafkaClientSpec {
  id: string;
  namespace: string;
  serviceAccountName: string;
  kafkaUserName: string;
  secretName: string;
  produceTopics: string[];
  consumeTopics: string[];
  dlqTopics: string[];
}

interface KafkaGroupCleanupPolicy {
  id: string;
  automatic: boolean;
  prefix: string;
  inactiveStates: Array<"Empty" | "Dead">;
  minimumGroupAgeHours: number;
  timestamp: {
    source: "group-name-regex";
    pattern: string;
    captureGroup: number;
    unit: "unix-ms";
  };
}

interface PlatformKafkaConfig {
  version: number;
  kind: "platform-infra-kafka";
  metadata: {
    id: string;
    owner: string;
    spec: string;
    relatedIssues: number[];
  };
  defaults: {
    targetId: string;
    switch: {
      enabled: boolean;
      mode: "durable-event-stream";
      appIntegrationEnabled: boolean;
      produceEnabled: boolean;
      consumeEnabled: boolean;
    };
  };
  operator: {
    implementation: "strimzi";
    version: string;
    manifestUrl: string;
    deploymentName: string;
    serviceAccountName: string;
    resources: ResourceBudget;
    crds: string[];
  };
  targets: KafkaTarget[];
  cluster: {
    name: string;
    nodePoolName: string;
    kafkaVersion: string;
    metadataVersion: string;
    replicas: number;
    resources: ResourceBudget;
    jvmOptions: JvmBudget;
    entityOperator: {
      topicOperator: EntityOperatorBudget;
      userOperator: EntityOperatorBudget;
    };
    storage: {
      size: string;
      deleteClaim: boolean;
    };
    listeners: {
      plain: { enabled: boolean; port: number };
      tls: { enabled: boolean; port: number };
    };
    authorization: {
      enabled: boolean;
      mode: string;
    };
  };
  topics: KafkaTopicSpec[];
  clients: KafkaClientSpec[];
  validation: {
    timeoutSeconds: number;
    pollSeconds: number;
    smokeTopic: string;
  };
  management: {
    replay: {
      defaultLimit: number;
      maxLimit: number;
      defaultTimeoutMs: number;
      maxTimeoutMs: number;
      commandGraceMs: number;
    };
    defaultTailLimit: number;
    maxTailLimit: number;
    defaultGroupListLimit: number;
    maxGroupListLimit: number;
    consumerGroupCleanup: {
      defaultCandidateLimit: number;
      maxCandidateLimit: number;
      commandTimeoutSeconds: number;
      deleteBatchSize: number;
      automatic: {
        enabled: boolean;
        schedule: string;
        image: string;
        consumerGroupsCommand: string;
        configMapName: string;
        cronJobNamePrefix: string;
        candidateLimit: number;
        activeDeadlineSeconds: number;
        startingDeadlineSeconds: number;
        successfulJobsHistoryLimit: number;
        failedJobsHistoryLimit: number;
        resources: ResourceBudget;
      };
      policies: KafkaGroupCleanupPolicy[];
    };
    defaultTopic: string;
    diagnosticProducerId: string;
  };
}

interface CommonOptions {
  targetId: string | null;
  full: boolean;
  raw: boolean;
}

interface ApplyOptions extends CommonOptions {
  dryRun: boolean;
  confirm: boolean;
  wait: boolean;
}

interface KafkaInspectOptions extends CommonOptions {
  topic: string | null;
  group: string | null;
  limit: number | null;
}

interface KafkaProduceOptions extends CommonOptions {
  topic: string | null;
  key: string | null;
  source: string;
  eventType: string;
  payload: string | null;
}

interface KafkaGroupCleanupOptions extends CommonOptions {
  policyId: string;
  confirm: boolean;
  limit: number | null;
}

export interface KafkaReplayOptions extends CommonOptions {
  sessionId: string;
  traceId: string | null;
  lane: string | null;
  limit: number | null;
  timeoutMs: number | null;
  output: "text" | "json" | "yaml";
}

export async function runPlatformInfraKafkaCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const [action = "plan"] = args;
  if (action === "plan") {
    const options = parseCommonOptions(args.slice(1));
    const result = plan(options);
    return options.full || options.raw ? result : renderPlan(result);
  }
  if (action === "apply") {
    const options = parseApplyOptions(args.slice(1));
    const result = await apply(config, options);
    return options.full || options.raw ? result : renderApply(result);
  }
  if (action === "status") {
    const options = parseCommonOptions(args.slice(1));
    const result = await status(config, options);
    return options.full || options.raw ? result : renderStatus(result);
  }
  if (action === "validate") return await validate(config, parseCommonOptions(args.slice(1)));
  if (action === "topics") {
    const options = parseInspectOptions(args.slice(1));
    const result = await topics(config, options);
    return options.full || options.raw ? result : renderTopics(result);
  }
  if (action === "groups") {
    if (args[1] === "cleanup") {
      const options = parseGroupCleanupOptions(args.slice(2));
      const result = await cleanupGroups(config, options);
      return options.full || options.raw ? result : renderGroupCleanup(result);
    }
    const options = parseInspectOptions(args.slice(1));
    const result = await groups(config, options);
    return options.full || options.raw ? result : renderGroups(result);
  }
  if (action === "offsets") {
    const options = parseInspectOptions(args.slice(1));
    const result = await offsets(config, options);
    return options.full || options.raw ? result : renderOffsets(result);
  }
  if (action === "tail") {
    const options = parseInspectOptions(args.slice(1));
    const result = await tail(config, options);
    return options.full || options.raw ? result : renderTail(result);
  }
  if (action === "replay") {
    const options = parseKafkaReplayOptions(args.slice(1));
    const result = await replayAgentRun(config, options);
    if (options.output === "json" || options.output === "yaml") return renderMachine("platform-infra kafka replay agentrun", result, options.output, result.ok !== false);
    return renderKafkaReplay(result);
  }
  if (action === "produce") return await produce(config, await parseProduceOptions(args.slice(1)));
  return {
    ok: false,
    error: "unsupported-platform-infra-kafka-command",
    args,
    help: kafkaHelp(),
  };
}

export function kafkaHelp(): Record<string, unknown> {
  return {
    command: "platform-infra kafka plan|apply|status|validate|topics|groups|offsets|tail|replay|produce",
    configTruth: configLabel,
    usage: [
      "bun scripts/cli.ts platform-infra kafka plan --target NC01",
      "bun scripts/cli.ts platform-infra kafka plan --node NC01",
      "bun scripts/cli.ts platform-infra kafka apply --target NC01 --dry-run",
      "bun scripts/cli.ts platform-infra kafka apply --target NC01 --confirm",
      "bun scripts/cli.ts platform-infra kafka status --target NC01 [--full|--raw]",
      "bun scripts/cli.ts platform-infra kafka validate --target NC01 [--full|--raw]",
      "bun scripts/cli.ts platform-infra kafka topics --node NC01",
      "bun scripts/cli.ts platform-infra kafka groups --node NC01 [--limit N] [--full|--raw]",
      "bun scripts/cli.ts platform-infra kafka groups cleanup --node NC01 --policy hwlab-cloud-api-sse [--confirm]",
      "bun scripts/cli.ts platform-infra kafka offsets --node NC01 [--topic hwlab.event.v1]",
      "bun scripts/cli.ts platform-infra kafka tail --node NC01 --topic hwlab.event.v1 --limit 5",
      "bun scripts/cli.ts platform-infra kafka replay agentrun --node NC01 --lane nc01-v02 --session-id <id> --trace-id <id> --no-publish [-o json|yaml]",
      "bun scripts/cli.ts platform-infra kafka produce --node NC01 --topic hwlab.event.v1 --key <trace-or-session>",
    ],
    boundary: "Kafka runtime belongs to platform-infra. Durable producers and fixed-group consumers are enabled; browser delivery remains a database-projected SSE concern.",
  };
}

function readKafkaConfig(): PlatformKafkaConfig {
  const root = readYamlRecord<Record<string, unknown>>(configFile, "platform-infra-kafka");
  const version = y.integerField(root, "version", "");
  if (version !== 1) throw new Error(`${configLabel}.version must be 1`);
  const metadata = y.objectField(root, "metadata", "");
  const defaults = y.objectField(root, "defaults", "");
  const switchRecord = y.objectField(defaults, "switch", "defaults");
  const operator = y.objectField(root, "operator", "");
  const operatorResources = y.objectField(operator, "resources", "operator");
  const cluster = y.objectField(root, "cluster", "");
  const clusterResources = y.objectField(cluster, "resources", "cluster");
  const clusterJvmOptions = y.objectField(cluster, "jvmOptions", "cluster");
  const entityOperator = y.objectField(cluster, "entityOperator", "cluster");
  const topicOperator = y.objectField(entityOperator, "topicOperator", "cluster.entityOperator");
  const userOperator = y.objectField(entityOperator, "userOperator", "cluster.entityOperator");
  const storage = y.objectField(cluster, "storage", "cluster");
  const listeners = y.objectField(cluster, "listeners", "cluster");
  const plain = y.objectField(listeners, "plain", "cluster.listeners");
  const tls = y.objectField(listeners, "tls", "cluster.listeners");
  const authorization = y.objectField(cluster, "authorization", "cluster");
  const validation = y.objectField(root, "validation", "");
  const parsed: PlatformKafkaConfig = {
    version,
    kind: "platform-infra-kafka",
    metadata: {
      id: y.stringField(metadata, "id", "metadata"),
      owner: y.stringField(metadata, "owner", "metadata"),
      spec: y.stringField(metadata, "spec", "metadata"),
      relatedIssues: y.numberArrayField(metadata, "relatedIssues", "metadata"),
    },
    defaults: {
      targetId: y.stringField(defaults, "targetId", "defaults"),
      switch: {
        enabled: y.booleanField(switchRecord, "enabled", "defaults.switch"),
        mode: y.enumField(switchRecord, "mode", "defaults.switch", ["durable-event-stream"] as const),
        appIntegrationEnabled: y.booleanField(switchRecord, "appIntegrationEnabled", "defaults.switch"),
        produceEnabled: y.booleanField(switchRecord, "produceEnabled", "defaults.switch"),
        consumeEnabled: y.booleanField(switchRecord, "consumeEnabled", "defaults.switch"),
      },
    },
    operator: {
      implementation: y.enumField(operator, "implementation", "operator", ["strimzi"] as const),
      version: y.stringField(operator, "version", "operator"),
      manifestUrl: y.httpsUrlField(operator, "manifestUrl", "operator"),
      deploymentName: y.kubernetesNameField(operator, "deploymentName", "operator"),
      serviceAccountName: y.kubernetesNameField(operator, "serviceAccountName", "operator"),
      resources: parseResourceBudget(operatorResources, "operator.resources"),
      crds: y.stringArrayField(operator, "crds", "operator"),
    },
    targets: y.arrayOfRecords(root.targets, "targets").map(parseTarget),
    cluster: {
      name: y.kubernetesNameField(cluster, "name", "cluster"),
      nodePoolName: y.kubernetesNameField(cluster, "nodePoolName", "cluster"),
      kafkaVersion: y.stringField(cluster, "kafkaVersion", "cluster"),
      metadataVersion: y.stringField(cluster, "metadataVersion", "cluster"),
      replicas: y.integerField(cluster, "replicas", "cluster"),
      resources: parseResourceBudget(clusterResources, "cluster.resources"),
      jvmOptions: parseJvmBudget(clusterJvmOptions, "cluster.jvmOptions"),
      entityOperator: {
        topicOperator: parseEntityOperatorBudget(topicOperator, "cluster.entityOperator.topicOperator"),
        userOperator: parseEntityOperatorBudget(userOperator, "cluster.entityOperator.userOperator"),
      },
      storage: {
        size: y.stringField(storage, "size", "cluster.storage"),
        deleteClaim: y.booleanField(storage, "deleteClaim", "cluster.storage"),
      },
      listeners: {
        plain: { enabled: y.booleanField(plain, "enabled", "cluster.listeners.plain"), port: y.portField(plain, "port", "cluster.listeners.plain") },
        tls: { enabled: y.booleanField(tls, "enabled", "cluster.listeners.tls"), port: y.portField(tls, "port", "cluster.listeners.tls") },
      },
      authorization: {
        enabled: y.booleanField(authorization, "enabled", "cluster.authorization"),
        mode: y.stringField(authorization, "mode", "cluster.authorization"),
      },
    },
    topics: y.arrayOfRecords(root.topics, "topics").map(parseTopic),
    clients: y.arrayOfRecords(root.clients, "clients").map(parseClient),
    validation: {
      timeoutSeconds: y.integerField(validation, "timeoutSeconds", "validation"),
      pollSeconds: y.integerField(validation, "pollSeconds", "validation"),
      smokeTopic: y.stringField(validation, "smokeTopic", "validation"),
    },
    management: parseManagement(root),
  };
  validateConfig(parsed);
  return parsed;
}

function parseTarget(record: Record<string, unknown>, index: number): KafkaTarget {
  const path = `targets[${index}]`;
  return {
    id: y.stringField(record, "id", path),
    route: y.stringField(record, "route", path),
    namespace: y.kubernetesNameField(record, "namespace", path),
    role: y.enumField(record, "role", path, ["active", "standby"] as const),
    enabled: y.booleanField(record, "enabled", path),
    createNamespace: y.booleanField(record, "createNamespace", path),
    storageClassName: y.stringField(record, "storageClassName", path),
  };
}

function parseResourceBudget(record: Record<string, unknown>, path: string): ResourceBudget {
  const requests = y.objectField(record, "requests", path);
  const limits = y.objectField(record, "limits", path);
  return {
    requests: {
      cpu: resourceQuantity(requests, "cpu", `${path}.requests`, "cpu"),
      memory: resourceQuantity(requests, "memory", `${path}.requests`, "memory"),
    },
    limits: {
      cpu: resourceQuantity(limits, "cpu", `${path}.limits`, "cpu"),
      memory: resourceQuantity(limits, "memory", `${path}.limits`, "memory"),
    },
  };
}

function parseJvmBudget(record: Record<string, unknown>, path: string): JvmBudget {
  const xms = y.stringField(record, "xms", path);
  const xmx = y.stringField(record, "xmx", path);
  if (!/^[1-9][0-9]*[mMgG]$/u.test(xms) || !/^[1-9][0-9]*[mMgG]$/u.test(xmx)) {
    throw new Error(`${configLabel}.${path} xms/xmx must be explicit m or g quantities`);
  }
  return { xms, xmx };
}

function parseEntityOperatorBudget(record: Record<string, unknown>, path: string): EntityOperatorBudget {
  return {
    resources: parseResourceBudget(y.objectField(record, "resources", path), `${path}.resources`),
    jvmOptions: parseJvmBudget(y.objectField(record, "jvmOptions", path), `${path}.jvmOptions`),
  };
}

function resourceQuantity(record: Record<string, unknown>, key: string, path: string, kind: "cpu" | "memory"): string {
  const value = y.stringField(record, key, path);
  const pattern = kind === "cpu" ? /^[1-9][0-9]*m$/u : /^[1-9][0-9]*Mi$/u;
  if (!pattern.test(value)) throw new Error(`${configLabel}.${path}.${key} must be an explicit ${kind === "cpu" ? "millicpu" : "Mi"} quantity`);
  return value;
}

function parseTopic(record: Record<string, unknown>, index: number): KafkaTopicSpec {
  const path = `topics[${index}]`;
  return {
    name: topicNameField(record, "name", path),
    partitions: positiveInteger(record, "partitions", path),
    replicas: positiveInteger(record, "replicas", path),
    retentionMs: positiveInteger(record, "retentionMs", path),
    cleanupPolicy: y.enumField(record, "cleanupPolicy", path, ["delete", "compact"] as const),
    description: y.stringField(record, "description", path),
  };
}

function parseClient(record: Record<string, unknown>, index: number): KafkaClientSpec {
  const path = `clients[${index}]`;
  return {
    id: y.stringField(record, "id", path),
    namespace: y.kubernetesNameField(record, "namespace", path),
    serviceAccountName: y.kubernetesNameField(record, "serviceAccountName", path),
    kafkaUserName: y.kubernetesNameField(record, "kafkaUserName", path),
    secretName: y.kubernetesNameField(record, "secretName", path),
    produceTopics: topicArray(record, "produceTopics", path),
    consumeTopics: topicArray(record, "consumeTopics", path),
    dlqTopics: topicArray(record, "dlqTopics", path),
  };
}

function parseManagement(root: Record<string, unknown>): PlatformKafkaConfig["management"] {
  const management = y.objectField(root, "management", "");
  const replay = y.objectField(management, "replay", "management");
  const cleanup = y.objectField(management, "consumerGroupCleanup", "management");
  const automatic = y.objectField(cleanup, "automatic", "management.consumerGroupCleanup");
  return {
    replay: {
      defaultLimit: positiveInteger(replay, "defaultLimit", "management.replay"),
      maxLimit: positiveInteger(replay, "maxLimit", "management.replay"),
      defaultTimeoutMs: positiveInteger(replay, "defaultTimeoutMs", "management.replay"),
      maxTimeoutMs: positiveInteger(replay, "maxTimeoutMs", "management.replay"),
      commandGraceMs: positiveInteger(replay, "commandGraceMs", "management.replay"),
    },
    defaultTailLimit: positiveInteger(management, "defaultTailLimit", "management"),
    maxTailLimit: positiveInteger(management, "maxTailLimit", "management"),
    defaultGroupListLimit: positiveInteger(management, "defaultGroupListLimit", "management"),
    maxGroupListLimit: positiveInteger(management, "maxGroupListLimit", "management"),
    consumerGroupCleanup: {
      defaultCandidateLimit: positiveInteger(cleanup, "defaultCandidateLimit", "management.consumerGroupCleanup"),
      maxCandidateLimit: positiveInteger(cleanup, "maxCandidateLimit", "management.consumerGroupCleanup"),
      commandTimeoutSeconds: positiveInteger(cleanup, "commandTimeoutSeconds", "management.consumerGroupCleanup"),
      deleteBatchSize: positiveInteger(cleanup, "deleteBatchSize", "management.consumerGroupCleanup"),
      automatic: {
        enabled: y.booleanField(automatic, "enabled", "management.consumerGroupCleanup.automatic"),
        schedule: y.stringField(automatic, "schedule", "management.consumerGroupCleanup.automatic"),
        image: y.stringField(automatic, "image", "management.consumerGroupCleanup.automatic"),
        consumerGroupsCommand: y.stringField(automatic, "consumerGroupsCommand", "management.consumerGroupCleanup.automatic"),
        configMapName: y.kubernetesNameField(automatic, "configMapName", "management.consumerGroupCleanup.automatic"),
        cronJobNamePrefix: y.kubernetesNameField(automatic, "cronJobNamePrefix", "management.consumerGroupCleanup.automatic"),
        candidateLimit: positiveInteger(automatic, "candidateLimit", "management.consumerGroupCleanup.automatic"),
        activeDeadlineSeconds: positiveInteger(automatic, "activeDeadlineSeconds", "management.consumerGroupCleanup.automatic"),
        startingDeadlineSeconds: positiveInteger(automatic, "startingDeadlineSeconds", "management.consumerGroupCleanup.automatic"),
        successfulJobsHistoryLimit: positiveInteger(automatic, "successfulJobsHistoryLimit", "management.consumerGroupCleanup.automatic"),
        failedJobsHistoryLimit: positiveInteger(automatic, "failedJobsHistoryLimit", "management.consumerGroupCleanup.automatic"),
        resources: parseResourceBudget(y.objectField(automatic, "resources", "management.consumerGroupCleanup.automatic"), "management.consumerGroupCleanup.automatic.resources"),
      },
      policies: y.arrayOfRecords(cleanup.policies, "management.consumerGroupCleanup.policies").map(parseGroupCleanupPolicy),
    },
    defaultTopic: topicNameField(management, "defaultTopic", "management"),
    diagnosticProducerId: y.stringField(management, "diagnosticProducerId", "management"),
  };
}

function parseGroupCleanupPolicy(record: Record<string, unknown>, index: number): KafkaGroupCleanupPolicy {
  const path = `management.consumerGroupCleanup.policies[${index}]`;
  const timestamp = y.objectField(record, "timestamp", path);
  const prefix = y.stringField(record, "prefix", path);
  if (!/^[A-Za-z0-9._-]+$/u.test(prefix) || !prefix.endsWith("-")) throw new Error(`${configLabel}.${path}.prefix must be a Kafka-safe, delimiter-terminated prefix`);
  const inactiveStates = y.stringArrayField(record, "inactiveStates", path).map((value) => {
    if (value !== "Empty" && value !== "Dead") throw new Error(`${configLabel}.${path}.inactiveStates only accepts Empty or Dead`);
    return value;
  });
  if (inactiveStates.length === 0) throw new Error(`${configLabel}.${path}.inactiveStates must not be empty`);
  const pattern = y.stringField(timestamp, "pattern", `${path}.timestamp`);
  try {
    new RegExp(pattern, "u");
  } catch (error) {
    throw new Error(`${configLabel}.${path}.timestamp.pattern is invalid: ${error instanceof Error ? error.message : String(error)}`);
  }
  return {
    id: y.stringField(record, "id", path),
    automatic: y.booleanField(record, "automatic", path),
    prefix,
    inactiveStates,
    minimumGroupAgeHours: positiveInteger(record, "minimumGroupAgeHours", path),
    timestamp: {
      source: y.enumField(timestamp, "source", `${path}.timestamp`, ["group-name-regex"] as const),
      pattern,
      captureGroup: positiveInteger(timestamp, "captureGroup", `${path}.timestamp`),
      unit: y.enumField(timestamp, "unit", `${path}.timestamp`, ["unix-ms"] as const),
    },
  };
}

function validateConfig(kafka: PlatformKafkaConfig): void {
  resolveTarget(kafka, kafka.defaults.targetId);
  if (!/^https:\/\/github\.com\/strimzi\/strimzi-kafka-operator\/releases\/download\//u.test(kafka.operator.manifestUrl)) {
    throw new Error(`${configLabel}.operator.manifestUrl must be an official Strimzi GitHub release URL`);
  }
  if (kafka.cluster.replicas !== 1) throw new Error(`${configLabel}.cluster.replicas must be 1 for the target-scoped Kafka POC`);
  if (!/^[0-9]+Gi$/u.test(kafka.cluster.storage.size)) throw new Error(`${configLabel}.cluster.storage.size must be a Gi quantity`);
  if (!kafka.topics.some((topic) => topic.name === kafka.validation.smokeTopic)) throw new Error(`${configLabel}.validation.smokeTopic must reference one of topics[].name`);
  if (!kafka.topics.some((topic) => topic.name === kafka.management.defaultTopic)) throw new Error(`${configLabel}.management.defaultTopic must reference one of topics[].name`);
  if (kafka.management.replay.defaultLimit > kafka.management.replay.maxLimit) throw new Error(`${configLabel}.management.replay.defaultLimit must be <= maxLimit`);
  if (kafka.management.replay.defaultTimeoutMs > kafka.management.replay.maxTimeoutMs) throw new Error(`${configLabel}.management.replay.defaultTimeoutMs must be <= maxTimeoutMs`);
  if (kafka.management.replay.maxTimeoutMs + kafka.management.replay.commandGraceMs >= 60_000) throw new Error(`${configLabel}.management.replay timeout plus command grace must stay below the trans short-connection budget`);
  if (kafka.management.defaultTailLimit > kafka.management.maxTailLimit) throw new Error(`${configLabel}.management.defaultTailLimit must be <= management.maxTailLimit`);
  if (kafka.management.defaultGroupListLimit > kafka.management.maxGroupListLimit) throw new Error(`${configLabel}.management.defaultGroupListLimit must be <= management.maxGroupListLimit`);
  if (kafka.management.consumerGroupCleanup.defaultCandidateLimit > kafka.management.consumerGroupCleanup.maxCandidateLimit) throw new Error(`${configLabel}.management.consumerGroupCleanup.defaultCandidateLimit must be <= maxCandidateLimit`);
  const automaticCleanup = kafka.management.consumerGroupCleanup.automatic;
  if (automaticCleanup.schedule.trim().split(/\s+/u).length !== 5) throw new Error(`${configLabel}.management.consumerGroupCleanup.automatic.schedule must contain five cron fields`);
  if (!/^[A-Za-z0-9._/-]+:[A-Za-z0-9._-]+$/u.test(automaticCleanup.image)) throw new Error(`${configLabel}.management.consumerGroupCleanup.automatic.image must be an explicit tagged image`);
  if (!/^\/[A-Za-z0-9._/-]+$/u.test(automaticCleanup.consumerGroupsCommand)) throw new Error(`${configLabel}.management.consumerGroupCleanup.automatic.consumerGroupsCommand must be an absolute path`);
  if (automaticCleanup.candidateLimit > kafka.management.consumerGroupCleanup.maxCandidateLimit) throw new Error(`${configLabel}.management.consumerGroupCleanup.automatic.candidateLimit must be <= maxCandidateLimit`);
  if (kafka.management.consumerGroupCleanup.deleteBatchSize > automaticCleanup.candidateLimit) throw new Error(`${configLabel}.management.consumerGroupCleanup.deleteBatchSize must be <= automatic.candidateLimit`);
  const cleanupPolicyIds = new Set<string>();
  const cleanupPrefixes = new Set<string>();
  for (const policy of kafka.management.consumerGroupCleanup.policies) {
    if (cleanupPolicyIds.has(policy.id)) throw new Error(`${configLabel}.management.consumerGroupCleanup.policies contains duplicate id ${policy.id}`);
    if (cleanupPrefixes.has(policy.prefix)) throw new Error(`${configLabel}.management.consumerGroupCleanup.policies contains duplicate prefix ${policy.prefix}`);
    cleanupPolicyIds.add(policy.id);
    cleanupPrefixes.add(policy.prefix);
  }
  if (automaticCleanup.enabled && !kafka.management.consumerGroupCleanup.policies.some((policy) => policy.automatic)) {
    throw new Error(`${configLabel}.management.consumerGroupCleanup.automatic.enabled requires at least one automatic policy`);
  }
  if (!kafka.defaults.switch.enabled || !kafka.defaults.switch.appIntegrationEnabled || !kafka.defaults.switch.produceEnabled || !kafka.defaults.switch.consumeEnabled) {
    throw new Error(`${configLabel}.defaults.switch must enable durable event production and consumption`);
  }
  const topicNames = new Set<string>();
  for (const topic of kafka.topics) {
    if (topicNames.has(topic.name)) throw new Error(`${configLabel}.topics contains duplicate topic ${topic.name}`);
    topicNames.add(topic.name);
  }
  const clientIds = new Set<string>();
  for (const client of kafka.clients) {
    if (clientIds.has(client.id)) throw new Error(`${configLabel}.clients contains duplicate id ${client.id}`);
    clientIds.add(client.id);
    for (const topic of [...client.produceTopics, ...client.consumeTopics, ...client.dlqTopics]) {
      if (!topicNames.has(topic)) throw new Error(`${configLabel}.clients.${client.id} references unknown topic ${topic}`);
    }
  }
  if (kafka.validation.timeoutSeconds < 5 || kafka.validation.timeoutSeconds > 55) throw new Error(`${configLabel}.validation.timeoutSeconds must be between 5 and 55`);
  if (kafka.validation.pollSeconds < 1 || kafka.validation.pollSeconds > kafka.validation.timeoutSeconds) throw new Error(`${configLabel}.validation.pollSeconds must be between 1 and timeoutSeconds`);
}

function resolveTarget(kafka: PlatformKafkaConfig, targetId: string | null): KafkaTarget {
  const resolved = targetId ?? kafka.defaults.targetId;
  const target = kafka.targets.find((item) => item.id.toLowerCase() === resolved.toLowerCase());
  if (target === undefined) throw new Error(`unknown kafka target ${resolved}; known targets: ${kafka.targets.map((item) => item.id).join(", ")}`);
  if (!target.enabled) throw new Error(`kafka target ${target.id} is disabled in ${configLabel}`);
  return target;
}

function plan(options: CommonOptions): Record<string, unknown> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const manifest = renderKafkaManifest(kafka, target);
  const policy = policyChecks(kafka, target, manifest);
  return {
    ok: policy.every((check) => check.ok),
    action: "platform-infra-kafka-plan",
    mutation: false,
    config: configSummary(kafka, target),
    renderPlan: {
      target: targetSummary(target),
      objects: manifestObjectSummary(manifest),
      operator: operatorSummary(kafka, target),
      cluster: clusterSummary(kafka, target),
      topics: kafka.topics.map((topic) => topicSummary(topic)),
      clients: kafka.clients.map((client) => clientSummary(client)),
    },
    policy,
    next: {
      dryRun: `bun scripts/cli.ts platform-infra kafka apply --target ${target.id} --dry-run`,
      apply: `bun scripts/cli.ts platform-infra kafka apply --target ${target.id} --confirm`,
      status: `bun scripts/cli.ts platform-infra kafka status --target ${target.id}`,
      validate: `bun scripts/cli.ts platform-infra kafka validate --target ${target.id}`,
    },
  };
}

async function apply(config: UniDeskConfig, options: ApplyOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const manifest = renderKafkaManifest(kafka, target);
  const policy = policyChecks(kafka, target, manifest);
  if (!policy.every((check) => check.ok)) return { ok: false, action: "platform-infra-kafka-apply", mode: "policy-blocked", mutation: false, policy };
  const operator = await fetchOperatorManifest(kafka, target);
  if (operator.ok !== true) {
    return {
      ok: false,
      action: "platform-infra-kafka-apply",
      mode: "operator-manifest-fetch-failed",
      mutation: false,
      target: targetSummary(target),
      config: compactConfigSummary(kafka, target),
      policy,
      operator,
    };
  }
  const result = await capture(config, target.route, ["sh"], applyScript(kafka, target, manifest, operator, options));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-apply",
    mode: options.dryRun ? "dry-run" : "confirmed",
    mutation: !options.dryRun,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    policy,
    remote: parsed ?? compactCapture(result, { full: true }),
    next: {
      status: `bun scripts/cli.ts platform-infra kafka status --target ${target.id}`,
      validate: `bun scripts/cli.ts platform-infra kafka validate --target ${target.id}`,
    },
  };
}

async function status(config: UniDeskConfig, options: CommonOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const result = await capture(config, target.route, ["sh"], statusScript(kafka, target, options.full));
  const parsed = parseJsonOutput(result.stdout);
  const summary = parsed === null ? null : statusSummary(parsed);
  return {
    ok: result.exitCode === 0 && summary?.ready === true,
    action: "platform-infra-kafka-status",
    mutation: false,
    target: targetSummary(target),
    config: configSummary(kafka, target),
    summary,
    remote: options.raw ? parsed : options.full ? parsed : summary ?? compactCapture(result, { full: true }),
    next: {
      plan: `bun scripts/cli.ts platform-infra kafka plan --target ${target.id}`,
      apply: `bun scripts/cli.ts platform-infra kafka apply --target ${target.id} --confirm`,
      validate: `bun scripts/cli.ts platform-infra kafka validate --target ${target.id}`,
    },
  };
}

async function validate(config: UniDeskConfig, options: CommonOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const result = await capture(config, target.route, ["sh"], validateScript(kafka, target, options.full));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-validate",
    mutation: true,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    validation: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function topics(config: UniDeskConfig, options: KafkaInspectOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const result = await capture(config, target.route, ["sh"], topicsScript(kafka, target));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-topics",
    mutation: false,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    query: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function groups(config: UniDeskConfig, options: KafkaInspectOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const limit = boundedGroupListLimit(kafka, options.limit);
  const result = await capture(config, target.route, ["sh"], groupsScript(kafka, target));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-groups",
    mutation: false,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    query: parsed ?? null,
    presentation: { limit },
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function cleanupGroups(config: UniDeskConfig, options: KafkaGroupCleanupOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const policy = kafka.management.consumerGroupCleanup.policies.find((item) => item.id === options.policyId);
  if (policy === undefined) throw new Error(`unknown Kafka consumer group cleanup policy ${options.policyId}; configured policies: ${kafka.management.consumerGroupCleanup.policies.map((item) => item.id).join(", ")}`);
  const candidateLimit = boundedGroupCleanupLimit(kafka, options.limit);
  const runtimeEnvironment = {
    KAFKA_GROUP_CONFIRM: options.confirm ? "true" : "false",
    KAFKA_TARGET: target.id,
    KAFKA_NAMESPACE: target.namespace,
    KAFKA_CLUSTER: kafka.cluster.name,
    KAFKA_BOOTSTRAP: brokerBootstrap(kafka),
    KAFKA_POLICY_B64: Buffer.from(JSON.stringify(policy), "utf8").toString("base64"),
    KAFKA_CANDIDATE_LIMIT: String(candidateLimit),
    KAFKA_FULL: options.full || options.raw ? "true" : "false",
    KAFKA_COMMAND_TIMEOUT_SECONDS: String(kafka.management.consumerGroupCleanup.commandTimeoutSeconds),
    KAFKA_DELETE_BATCH_SIZE: String(kafka.management.consumerGroupCleanup.deleteBatchSize),
  };
  const remoteScript = [
    ...Object.entries(runtimeEnvironment).map(([key, value]) => `export ${key}=${shQuote(value)}`),
    "python3 - <<'PY'",
    kafkaConsumerGroupsNativeScript.trimEnd(),
    "PY",
  ].join("\n");
  const result = await capture(config, target.route, ["sh"], remoteScript);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-groups-cleanup",
    mode: options.confirm ? "confirmed" : "plan",
    mutation: options.confirm,
    target: targetSummary(target),
    config: { configPath: configLabel, policyId: policy.id, valuesPrinted: false },
    cleanup: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
    next: {
      plan: `bun scripts/cli.ts platform-infra kafka groups cleanup --node ${target.id} --policy ${policy.id}`,
      confirm: `bun scripts/cli.ts platform-infra kafka groups cleanup --node ${target.id} --policy ${policy.id} --confirm`,
      groups: `bun scripts/cli.ts platform-infra kafka groups --node ${target.id}`,
    },
  };
}

async function offsets(config: UniDeskConfig, options: KafkaInspectOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const topic = resolveTopic(kafka, options.topic, null);
  const result = await capture(config, target.route, ["sh"], offsetsScript(kafka, target, topic, options.group));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-offsets",
    mutation: false,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    query: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function tail(config: UniDeskConfig, options: KafkaInspectOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const topic = resolveTopic(kafka, options.topic, kafka.management.defaultTopic);
  const limit = boundedLimit(kafka, options.limit);
  const result = await capture(config, target.route, ["sh"], tailScript(kafka, target, topic, limit));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-tail",
    mutation: false,
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    query: parsed ?? null,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function replayAgentRun(config: UniDeskConfig, options: KafkaReplayOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const lane = resolveAgentRunLaneTarget({ node: target.id, lane: options.lane }).spec;
  if (lane.nodeId !== target.id) throw new Error(`AgentRun lane ${lane.lane} belongs to ${lane.nodeId}, not Kafka target ${target.id}`);
  const inputTopic = resolveTopic(kafka, "codex-stdio.raw.v1", null);
  if (inputTopic === null) throw new Error("Kafka replay input topic codex-stdio.raw.v1 is not declared");
  const limit = options.limit ?? kafka.management.replay.defaultLimit;
  if (!Number.isInteger(limit) || limit < 1 || limit > kafka.management.replay.maxLimit) throw new Error(`Kafka replay --limit must be an integer from 1 to ${kafka.management.replay.maxLimit}`);
  const timeoutMs = options.timeoutMs ?? kafka.management.replay.defaultTimeoutMs;
  if (!Number.isInteger(timeoutMs) || timeoutMs < 250 || timeoutMs > kafka.management.replay.maxTimeoutMs) throw new Error(`Kafka replay --timeout-ms must be an integer from 250 to ${kafka.management.replay.maxTimeoutMs}`);
  const runtimeEnvironment = {
    KAFKA_NAMESPACE: target.namespace,
    KAFKA_CLUSTER: kafka.cluster.name,
    KAFKA_BOOTSTRAP: brokerBootstrap(kafka),
    KAFKA_INPUT_TOPIC: inputTopic,
    KAFKA_REPLAY_SESSION_ID: options.sessionId,
    KAFKA_REPLAY_TRACE_ID: options.traceId ?? "",
    KAFKA_REPLAY_LIMIT: String(limit),
    KAFKA_REPLAY_TIMEOUT_MS: String(timeoutMs),
    KAFKA_REPLAY_COMMAND_GRACE_MS: String(kafka.management.replay.commandGraceMs),
    AGENTRUN_NAMESPACE: lane.runtime.namespace,
    AGENTRUN_MANAGER_DEPLOYMENT: lane.runtime.managerDeployment,
  };
  const remoteScript = [
    ...Object.entries(runtimeEnvironment).map(([key, value]) => `export ${key}=${shQuote(value)}`),
    "python3 - <<'PY'",
    kafkaReplayDiagnosticsNativeScript.trimEnd(),
    "PY",
  ].join("\n");
  const result = await capture(config, target.route, ["sh"], remoteScript);
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-replay-agentrun",
    mode: "no-publish",
    mutation: false,
    target: targetSummary(target),
    lane: { node: lane.nodeId, lane: lane.lane, namespace: lane.runtime.namespace, managerDeployment: lane.runtime.managerDeployment },
    diagnosis: parsed,
    remote: options.raw && parsed !== null ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

async function produce(config: UniDeskConfig, options: KafkaProduceOptions): Promise<Record<string, unknown>> {
  const kafka = readKafkaConfig();
  const target = resolveTarget(kafka, options.targetId);
  const topic = resolveTopic(kafka, options.topic, kafka.management.defaultTopic);
  const payload = buildDiagnosticPayload(kafka, target, options, topic);
  const result = await capture(config, target.route, ["sh"], produceScript(kafka, target, topic, options.key, payload));
  const parsed = parseJsonOutput(result.stdout);
  return {
    ok: result.exitCode === 0 && parsed?.ok === true,
    action: "platform-infra-kafka-produce",
    mutation: true,
    mode: "diagnostic-produce",
    target: targetSummary(target),
    config: compactConfigSummary(kafka, target),
    production: parsed ?? null,
    remote: options.raw ? parsed : compactCapture(result, { full: options.full || result.exitCode !== 0 }),
  };
}

function renderKafkaManifest(kafka: PlatformKafkaConfig, target: KafkaTarget): string {
  const listeners = [
    kafka.cluster.listeners.plain.enabled
      ? `      - name: plain
        port: ${kafka.cluster.listeners.plain.port}
        type: internal
        tls: false`
      : "",
    kafka.cluster.listeners.tls.enabled
      ? `      - name: tls
        port: ${kafka.cluster.listeners.tls.port}
        type: internal
        tls: true`
      : "",
  ].filter(Boolean).join("\n");
  const topicDocs = kafka.topics.map((topic) => kafkaTopicManifest(kafka, target, topic)).join("---\n");
  const userDocs = kafka.clients.map((client) => kafkaUserManifest(kafka, target, client)).join("---\n");
  const retentionDocs = renderConsumerGroupRetention(kafka, target);
  return `apiVersion: v1
kind: Namespace
metadata:
  name: ${target.namespace}
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - {}
  egress:
    - {}
---
apiVersion: kafka.strimzi.io/v1
kind: KafkaNodePool
metadata:
  name: ${kafka.cluster.nodePoolName}
  namespace: ${target.namespace}
  labels:
    strimzi.io/cluster: ${kafka.cluster.name}
    app.kubernetes.io/name: ${kafka.cluster.name}
    app.kubernetes.io/component: kafka-node-pool
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  replicas: ${kafka.cluster.replicas}
  roles:
    - controller
    - broker
  resources:
${renderResourceBudget(kafka.cluster.resources, 4)}
  jvmOptions:
    "-Xms": ${kafka.cluster.jvmOptions.xms}
    "-Xmx": ${kafka.cluster.jvmOptions.xmx}
  storage:
    type: jbod
    volumes:
      - id: 0
        type: persistent-claim
        size: ${kafka.cluster.storage.size}
        class: ${target.storageClassName}
        deleteClaim: ${kafka.cluster.storage.deleteClaim}
        kraftMetadata: shared
---
apiVersion: kafka.strimzi.io/v1
kind: Kafka
metadata:
  name: ${kafka.cluster.name}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${kafka.cluster.name}
    app.kubernetes.io/component: kafka
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: ${target.id}
  annotations:
    unidesk.ai/spec: ${kafka.metadata.spec}
    unidesk.ai/app-integration-enabled: "${kafka.defaults.switch.appIntegrationEnabled}"
    unidesk.ai/event-stream-mode: "${kafka.defaults.switch.mode}"
    unidesk.ai/event-produce-enabled: "${kafka.defaults.switch.produceEnabled}"
    unidesk.ai/event-consume-enabled: "${kafka.defaults.switch.consumeEnabled}"
spec:
  kafka:
    version: ${kafka.cluster.kafkaVersion}
    metadataVersion: ${kafka.cluster.metadataVersion}
    listeners:
${listeners}
    config:
      offsets.topic.replication.factor: 1
      transaction.state.log.replication.factor: 1
      transaction.state.log.min.isr: 1
      default.replication.factor: 1
      min.insync.replicas: 1
      auto.create.topics.enable: false
  entityOperator:
    topicOperator:
      resources:
${renderResourceBudget(kafka.cluster.entityOperator.topicOperator.resources, 8)}
      jvmOptions:
        "-Xms": ${kafka.cluster.entityOperator.topicOperator.jvmOptions.xms}
        "-Xmx": ${kafka.cluster.entityOperator.topicOperator.jvmOptions.xmx}
    userOperator:
      resources:
${renderResourceBudget(kafka.cluster.entityOperator.userOperator.resources, 8)}
      jvmOptions:
        "-Xms": ${kafka.cluster.entityOperator.userOperator.jvmOptions.xms}
        "-Xmx": ${kafka.cluster.entityOperator.userOperator.jvmOptions.xmx}
---
${topicDocs}---\n${userDocs}${retentionDocs}`;
}

function renderResourceBudget(resources: ResourceBudget, indent: number): string {
  const prefix = " ".repeat(indent);
  return `${prefix}requests:
${prefix}  cpu: ${resources.requests.cpu}
${prefix}  memory: ${resources.requests.memory}
${prefix}limits:
${prefix}  cpu: ${resources.limits.cpu}
${prefix}  memory: ${resources.limits.memory}`;
}

function renderConsumerGroupRetention(kafka: PlatformKafkaConfig, target: KafkaTarget): string {
  const automatic = kafka.management.consumerGroupCleanup.automatic;
  if (!automatic.enabled) return "";
  const policies = kafka.management.consumerGroupCleanup.policies.filter((policy) => policy.automatic);
  const script = kafkaConsumerGroupRetentionNativeScript.trimEnd().split("\n").map((line) => `    ${line}`).join("\n");
  const jobs = policies.map((policy) => `---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ${automatic.cronJobNamePrefix}-${policy.id}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${automatic.cronJobNamePrefix}-${policy.id}
    app.kubernetes.io/component: kafka-group-retention
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/kafka-group-policy: ${policy.id}
spec:
  schedule: ${JSON.stringify(automatic.schedule)}
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: ${automatic.startingDeadlineSeconds}
  successfulJobsHistoryLimit: ${automatic.successfulJobsHistoryLimit}
  failedJobsHistoryLimit: ${automatic.failedJobsHistoryLimit}
  jobTemplate:
    spec:
      activeDeadlineSeconds: ${automatic.activeDeadlineSeconds}
      template:
        metadata:
          labels:
            app.kubernetes.io/name: ${automatic.cronJobNamePrefix}-${policy.id}
            app.kubernetes.io/component: kafka-group-retention
            app.kubernetes.io/part-of: platform-infra
            app.kubernetes.io/managed-by: unidesk
        spec:
          restartPolicy: Never
          containers:
            - name: retention
              image: ${automatic.image}
              imagePullPolicy: IfNotPresent
              command:
                - /bin/bash
                - /opt/unidesk/kafka-consumer-group-retention.sh
              env:
                - name: KAFKA_BOOTSTRAP_SERVER
                  value: ${JSON.stringify(brokerBootstrap(kafka))}
                - name: KAFKA_CONSUMER_GROUPS_COMMAND
                  value: ${JSON.stringify(automatic.consumerGroupsCommand)}
                - name: KAFKA_POLICY_ID
                  value: ${JSON.stringify(policy.id)}
                - name: KAFKA_GROUP_PREFIX
                  value: ${JSON.stringify(policy.prefix)}
                - name: KAFKA_GROUP_PATTERN
                  value: ${JSON.stringify(policy.timestamp.pattern)}
                - name: KAFKA_TIMESTAMP_CAPTURE_GROUP
                  value: ${JSON.stringify(String(policy.timestamp.captureGroup))}
                - name: KAFKA_INACTIVE_STATES
                  value: ${JSON.stringify(policy.inactiveStates.join(","))}
                - name: KAFKA_MINIMUM_AGE_HOURS
                  value: ${JSON.stringify(String(policy.minimumGroupAgeHours))}
                - name: KAFKA_CANDIDATE_LIMIT
                  value: ${JSON.stringify(String(automatic.candidateLimit))}
                - name: KAFKA_DELETE_BATCH_SIZE
                  value: ${JSON.stringify(String(kafka.management.consumerGroupCleanup.deleteBatchSize))}
                - name: KAFKA_COMMAND_TIMEOUT_SECONDS
                  value: ${JSON.stringify(String(kafka.management.consumerGroupCleanup.commandTimeoutSeconds))}
              resources:
${renderResourceBudget(automatic.resources, 16)}
              volumeMounts:
                - name: retention-script
                  mountPath: /opt/unidesk/kafka-consumer-group-retention.sh
                  subPath: kafka-consumer-group-retention.sh
                  readOnly: true
          volumes:
            - name: retention-script
              configMap:
                name: ${automatic.configMapName}
                defaultMode: 0555
`).join("");
  return `---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ${automatic.configMapName}
  namespace: ${target.namespace}
  labels:
    app.kubernetes.io/name: ${automatic.configMapName}
    app.kubernetes.io/component: kafka-group-retention
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
data:
  kafka-consumer-group-retention.sh: |-
${script}
${jobs}`;
}

function kafkaTopicManifest(kafka: PlatformKafkaConfig, target: KafkaTarget, topic: KafkaTopicSpec): string {
  return `apiVersion: kafka.strimzi.io/v1
kind: KafkaTopic
metadata:
  name: ${topicResourceName(topic.name)}
  namespace: ${target.namespace}
  labels:
    strimzi.io/cluster: ${kafka.cluster.name}
    app.kubernetes.io/name: ${topicResourceName(topic.name)}
    app.kubernetes.io/component: kafka-topic
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
  annotations:
    unidesk.ai/topic-name: ${topic.name}
    unidesk.ai/description: ${quoteAnnotation(topic.description)}
spec:
  topicName: ${topic.name}
  partitions: ${topic.partitions}
  replicas: ${topic.replicas}
  config:
    retention.ms: ${topic.retentionMs}
    cleanup.policy: ${topic.cleanupPolicy}
`;
}

function kafkaUserManifest(kafka: PlatformKafkaConfig, target: KafkaTarget, client: KafkaClientSpec): string {
  const authorization = kafka.cluster.authorization.enabled
    ? `  authorization:
    type: simple
    acls:
${clientAcls(client)}`
    : "";
  return `apiVersion: kafka.strimzi.io/v1
kind: KafkaUser
metadata:
  name: ${client.kafkaUserName}
  namespace: ${target.namespace}
  labels:
    strimzi.io/cluster: ${kafka.cluster.name}
    app.kubernetes.io/name: ${client.kafkaUserName}
    app.kubernetes.io/component: kafka-client
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
  annotations:
    unidesk.ai/client-id: ${client.id}
    unidesk.ai/client-namespace: ${client.namespace}
    unidesk.ai/client-service-account: ${client.serviceAccountName}
    unidesk.ai/secret-target: ${client.namespace}/${client.secretName}
spec:
  authentication:
    type: tls
${authorization}`;
}

function clientAcls(client: KafkaClientSpec): string {
  const lines: string[] = [];
  for (const topic of client.produceTopics) {
    lines.push(`      - resource:
          type: topic
          name: ${topic}
          patternType: literal
        operations:
          - Write
          - Describe`);
  }
  for (const topic of client.consumeTopics) {
    lines.push(`      - resource:
          type: topic
          name: ${topic}
          patternType: literal
        operations:
          - Read
          - Describe`);
  }
  for (const topic of client.dlqTopics) {
    lines.push(`      - resource:
          type: topic
          name: ${topic}
          patternType: literal
        operations:
          - Write
          - Describe`);
  }
  lines.push(`      - resource:
          type: group
          name: ${client.id}
          patternType: prefix
        operations:
          - Read`);
  return lines.join("\n");
}

async function fetchOperatorManifest(kafka: PlatformKafkaConfig, target: KafkaTarget): Promise<Record<string, unknown> & { ok: boolean; manifest?: string }> {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), 30_000);
  try {
    const response = await fetch(kafka.operator.manifestUrl, { signal: controller.signal });
    if (!response.ok) {
      return {
        ok: false,
        url: kafka.operator.manifestUrl,
        status: response.status,
        statusText: response.statusText,
      };
    }
    const source = await response.text();
    const manifest = source.replaceAll("namespace: myproject", `namespace: ${target.namespace}`);
    if (!manifest.includes("kind: CustomResourceDefinition") || !manifest.includes(`namespace: ${target.namespace}`)) {
      return {
        ok: false,
        url: kafka.operator.manifestUrl,
        error: "unexpected-strimzi-operator-manifest-shape",
        bytes: Buffer.byteLength(source, "utf8"),
      };
    }
    return {
      ok: true,
      url: kafka.operator.manifestUrl,
      bytes: Buffer.byteLength(source, "utf8"),
      sha256: sha256Hex(source),
      namespaceRewrite: target.namespace,
      manifest,
    };
  } catch (error) {
    return {
      ok: false,
      url: kafka.operator.manifestUrl,
      error: error instanceof Error ? error.message : String(error),
    };
  } finally {
    clearTimeout(timer);
  }
}

function applyScript(kafka: PlatformKafkaConfig, target: KafkaTarget, manifest: string, operator: Record<string, unknown> & { manifest?: string }, options: ApplyOptions): string {
  const dryRun = options.dryRun;
  const mode = dryRun ? "dry-run" : "confirmed";
  const dryServer = dryRun ? "--dry-run=server " : "";
  const stepTimeoutSeconds = Math.max(5, Math.min(kafka.validation.timeoutSeconds, 20));
  const checkTimeoutSeconds = Math.max(5, Math.min(kafka.validation.pollSeconds, 10));
  const operatorManifest = operator.manifest ?? "";
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
operator="$tmp/strimzi-operator.yaml"
operator_dir="$tmp/operator"
manifest="$tmp/kafka.k8s.yaml"
mkdir -p "$operator_dir"
cat >"$operator" <<'UNIDESK_STRIMZI_OPERATOR_YAML'
${operatorManifest}
UNIDESK_STRIMZI_OPERATOR_YAML
cp "$operator" "$operator_dir/strimzi-operator.yaml"
cat >"$operator_dir/kustomization.yaml" <<'UNIDESK_STRIMZI_KUSTOMIZATION_YAML'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - strimzi-operator.yaml
patches:
  - target:
      kind: Deployment
      name: ${kafka.operator.deploymentName}
    patch: |-
      - op: replace
        path: /spec/template/spec/containers/0/resources
        value:
${renderResourceBudget(kafka.operator.resources, 10)}
UNIDESK_STRIMZI_KUSTOMIZATION_YAML
cat >"$manifest" <<'UNIDESK_KAFKA_RUNTIME_YAML'
${manifest}
UNIDESK_KAFKA_RUNTIME_YAML

kubectl create namespace ${target.namespace} --dry-run=client -o yaml >"$tmp/ns.yaml" 2>"$tmp/ns-create.err"
ns_create_rc=$?
if [ "$ns_create_rc" -eq 0 ]; then
  timeout ${stepTimeoutSeconds} kubectl apply --server-side ${dryServer}--force-conflicts --field-manager=${fieldManager} -f "$tmp/ns.yaml" >"$tmp/ns.out" 2>"$tmp/ns.err"
  ns_rc=$?
else
  ns_rc=1
  : >"$tmp/ns.out"
  cp "$tmp/ns-create.err" "$tmp/ns.err"
fi

if [ "$ns_rc" -eq 0 ]; then
  timeout ${stepTimeoutSeconds} kubectl -n ${target.namespace} apply --server-side ${dryServer}--force-conflicts --validate=false --field-manager=${fieldManager} -k "$operator_dir" >"$tmp/operator.out" 2>"$tmp/operator.err"
  operator_rc=$?
else
  operator_rc=1
  printf '%s\\n' 'namespace apply failed; operator skipped' >"$tmp/operator.err"
  : >"$tmp/operator.out"
fi

if [ "$operator_rc" -eq 0 ]; then
  timeout ${checkTimeoutSeconds} kubectl get ${kafka.operator.crds.map((name) => `crd/${name}`).join(" ")} >"$tmp/crd-wait.out" 2>"$tmp/crd-wait.err"
  crd_ready_rc=$?
else
  crd_ready_rc=1
  printf '%s\\n' 'operator apply failed; CRD check skipped' >"$tmp/crd-wait.err"
  : >"$tmp/crd-wait.out"
fi

if [ "$operator_rc" -eq 0 ] && [ "$crd_ready_rc" -eq 0 ]; then
  timeout ${stepTimeoutSeconds} kubectl -n ${target.namespace} apply --server-side ${dryServer}--force-conflicts --validate=false --field-manager=${fieldManager} -f "$manifest" >"$tmp/kafka.out" 2>"$tmp/kafka.err"
  kafka_rc=$?
elif [ "$operator_rc" -eq 0 ] && [ "${dryRun ? "1" : "0"}" = "1" ]; then
  kafka_rc=0
  printf '%s\\n' 'dry-run: Kafka CR server validation skipped because Strimzi CRDs are not installed yet; operator dry-run succeeded.' >"$tmp/kafka.out"
  cp "$tmp/crd-wait.err" "$tmp/kafka.err"
else
  kafka_rc=1
  printf '%s\\n' 'Kafka CR apply skipped because Strimzi CRDs are not ready.' >"$tmp/kafka.err"
  : >"$tmp/kafka.out"
fi
python3 - "$tmp" "$ns_rc" "$operator_rc" "$crd_ready_rc" "$kafka_rc" <<'PY'
import json, os, sys
tmp = sys.argv[1]
ns_rc, operator_rc, crd_ready_rc, kafka_rc = [int(value) for value in sys.argv[2:6]]
def text(name, limit=1800):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
kafka_skipped_for_missing_crds = operator_rc == 0 and crd_ready_rc != 0 and kafka_rc == 0
payload = {
    "ok": ${dryRun ? "ns_rc == 0 and operator_rc == 0 and kafka_rc == 0" : "ns_rc == 0 and operator_rc == 0 and crd_ready_rc == 0 and kafka_rc == 0"},
    "target": "${target.id}",
    "route": "${target.route}",
    "namespace": "${target.namespace}",
    "mode": "${mode}",
    "mutation": ${dryRun ? "False" : "True"},
    "operator": {
        "implementation": "${kafka.operator.implementation}",
        "version": "${kafka.operator.version}",
        "manifestUrl": "${kafka.operator.manifestUrl}",
        "manifestSha256": "${stringValue(operator.sha256)}",
        "manifestBytes": ${Number(operator.bytes ?? 0)},
        "namespaceRewrite": "${target.namespace}",
    },
    "cluster": {
        "name": "${kafka.cluster.name}",
        "bootstrap": "${bootstrapService(kafka, target)}",
        "storage": "${kafka.cluster.storage.size}",
        "replicas": ${kafka.cluster.replicas},
    },
    "steps": {
        "namespace": {"exitCode": ns_rc, "stdoutTail": text("ns.out"), "stderrTail": text("ns.err")},
        "operatorApply": {"exitCode": operator_rc, "stdoutTail": text("operator.out"), "stderrTail": text("operator.err")},
        "crdPresent": {"exitCode": crd_ready_rc, "stdoutTail": text("crd-wait.out"), "stderrTail": text("crd-wait.err")},
        "kafkaApply": {"exitCode": kafka_rc, "skippedForMissingCrds": kafka_skipped_for_missing_crds, "stdoutTail": text("kafka.out"), "stderrTail": text("kafka.err")},
    },
    "valuesPrinted": False,
    "next": {
        "status": "bun scripts/cli.ts platform-infra kafka status --target ${target.id}",
        "validate": "bun scripts/cli.ts platform-infra kafka validate --target ${target.id}"
    }
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function statusScript(kafka: PlatformKafkaConfig, target: KafkaTarget, full: boolean): string {
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
capture_json() {
  name="$1"
  shift
  "$@" -o json >"$tmp/$name.json" 2>"$tmp/$name.err"
  rc=$?
  printf '%s' "$rc" >"$tmp/$name.rc"
}
capture_json ns kubectl get namespace ${target.namespace}
capture_json crds kubectl get ${kafka.operator.crds.map((name) => `crd/${name}`).join(" ")}
capture_json operator kubectl -n ${target.namespace} get deployment ${kafka.operator.deploymentName}
capture_json kafka kubectl -n ${target.namespace} get kafka.kafka.strimzi.io ${kafka.cluster.name}
capture_json nodepool kubectl -n ${target.namespace} get kafkanodepool.kafka.strimzi.io ${kafka.cluster.nodePoolName}
capture_json topics kubectl -n ${target.namespace} get kafkatopic.kafka.strimzi.io -l strimzi.io/cluster=${kafka.cluster.name}
capture_json users kubectl -n ${target.namespace} get kafkauser.kafka.strimzi.io -l strimzi.io/cluster=${kafka.cluster.name}
capture_json pods kubectl -n ${target.namespace} get pods -l strimzi.io/cluster=${kafka.cluster.name}
capture_json services kubectl -n ${target.namespace} get service -l strimzi.io/cluster=${kafka.cluster.name}
capture_json retention kubectl -n ${target.namespace} get cronjob -l app.kubernetes.io/component=kafka-group-retention
capture_json secrets kubectl -n ${target.namespace} get secret ${kafka.clients.map((client) => client.secretName).join(" ")}
capture_json events kubectl -n ${target.namespace} get events --sort-by=.lastTimestamp
python3 - "$tmp" <<'PY'
import json, os, sys
tmp = sys.argv[1]
expected_topics = ${JSON.stringify(kafka.topics.map((topic) => topic.name))}
expected_clients = ${JSON.stringify(kafka.clients.map((client) => client.kafkaUserName))}
expected_retention = ${JSON.stringify(kafka.management.consumerGroupCleanup.automatic.enabled ? kafka.management.consumerGroupCleanup.policies.filter((policy) => policy.automatic).map((policy) => `${kafka.management.consumerGroupCleanup.automatic.cronJobNamePrefix}-${policy.id}`) : [])}
def rc(name):
    try:
        return int(open(os.path.join(tmp, f"{name}.rc"), encoding="utf-8").read() or "1")
    except FileNotFoundError:
        return 1
def load(name):
    try:
        return json.load(open(os.path.join(tmp, f"{name}.json"), encoding="utf-8"))
    except Exception:
        return None
def items(name):
    data = load(name)
    if isinstance(data, dict) and isinstance(data.get("items"), list):
        return data["items"]
    if isinstance(data, dict) and data.get("kind") != "Status":
        return [data]
    return []
def meta_name(item):
    return ((item or {}).get("metadata") or {}).get("name")
def conditions(item):
    return (((item or {}).get("status") or {}).get("conditions") or [])
def condition_ready(item):
    return any(c.get("type") == "Ready" and c.get("status") == "True" for c in conditions(item))
def deployment_ready(item):
    spec = (item or {}).get("spec") or {}
    status = (item or {}).get("status") or {}
    desired = spec.get("replicas", 1)
    available = status.get("availableReplicas", 0)
    return {"name": meta_name(item), "desired": desired, "available": available, "ready": available >= desired}
def pod_summary(item):
    status = (item or {}).get("status") or {}
    return {"name": meta_name(item), "phase": status.get("phase"), "ready": any(c.get("type") == "Ready" and c.get("status") == "True" for c in status.get("conditions", []))}
def service_summary(item):
    spec = (item or {}).get("spec") or {}
    return {"name": meta_name(item), "type": spec.get("type"), "clusterIP": spec.get("clusterIP"), "ports": [{"name": p.get("name"), "port": p.get("port")} for p in spec.get("ports", [])]}
def topic_summary(item):
    spec = (item or {}).get("spec") or {}
    return {"resource": meta_name(item), "topicName": spec.get("topicName"), "ready": condition_ready(item)}
def user_summary(item):
    status = (item or {}).get("status") or {}
    return {"name": meta_name(item), "ready": condition_ready(item), "secret": status.get("secret")}
def retention_summary(item):
    spec = (item or {}).get("spec") or {}
    status = (item or {}).get("status") or {}
    return {
        "name": meta_name(item),
        "schedule": spec.get("schedule"),
        "suspended": spec.get("suspend", False),
        "active": len(status.get("active") or []),
        "lastScheduleTime": status.get("lastScheduleTime"),
        "lastSuccessfulTime": status.get("lastSuccessfulTime"),
    }
operator = deployment_ready(load("operator") or {})
kafka_obj = load("kafka") or {}
nodepool_obj = load("nodepool") or {}
topics = [topic_summary(item) for item in items("topics")]
users = [user_summary(item) for item in items("users")]
for name in expected_topics:
    if not any(item["topicName"] == name for item in topics):
        topics.append({"resource": "missing", "topicName": name, "ready": False})
for name in expected_clients:
    if not any(item["name"] == name for item in users):
        users.append({"name": name, "ready": False, "secret": None})
topic_ready = all(any(item["topicName"] == name and item["ready"] for item in topics) for name in expected_topics)
user_ready = all(any(item["name"] == name and item["ready"] for item in users) for name in expected_clients)
secrets = items("secrets")
retention = [retention_summary(item) for item in items("retention")]
retention_ready = rc("retention") == 0 and all(any(item["name"] == name and not item["suspended"] for item in retention) for name in expected_retention)
pods = [pod_summary(item) for item in items("pods")]
pods_ready = len(pods) > 0 and all(item["phase"] == "Running" and item["ready"] for item in pods)
payload = {
    "ready": rc("ns") == 0 and rc("crds") == 0 and operator["ready"] and condition_ready(kafka_obj) and topic_ready and user_ready and retention_ready and pods_ready,
    "target": "${target.id}",
    "route": "${target.route}",
    "namespace": "${target.namespace}",
    "operator": operator,
    "cluster": {
        "name": "${kafka.cluster.name}",
        "ready": condition_ready(kafka_obj),
        "conditions": conditions(kafka_obj),
        "bootstrap": "${bootstrapService(kafka, target)}",
        "plain": "${kafka.cluster.name}-kafka-bootstrap.${target.namespace}.svc.cluster.local:${kafka.cluster.listeners.plain.port}",
        "tls": "${kafka.cluster.name}-kafka-bootstrap.${target.namespace}.svc.cluster.local:${kafka.cluster.listeners.tls.port}",
    },
    "crdsReady": rc("crds") == 0,
    "nodePoolReady": rc("nodepool") == 0 and (condition_ready(nodepool_obj) or condition_ready(kafka_obj)),
    "topicReady": topic_ready,
    "userReady": user_ready,
    "retentionReady": retention_ready,
    "retention": retention,
    "podsReady": pods_ready,
    "topics": topics,
    "users": users,
    "pods": pods,
    "services": [service_summary(item) for item in items("services")],
    "clientSecrets": [{"name": meta_name(item), "keys": sorted(((item or {}).get("data") or {}).keys()), "valuesPrinted": False} for item in secrets],
    "valuesPrinted": False,
}
if ${full ? "False" : "True"}:
    payload["cluster"]["conditions"] = [{"type": c.get("type"), "status": c.get("status"), "reason": c.get("reason")} for c in payload["cluster"]["conditions"]]
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ready"] else 1)
PY
`;
}

function validateScript(kafka: PlatformKafkaConfig, target: KafkaTarget, full: boolean): string {
  const topic = kafka.validation.smokeTopic;
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name} -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
payload="unidesk-kafka-smoke-${target.id}-$(date +%s)-$$"
printf '%s' "$payload" >"$tmp/payload.txt"
if [ -n "$pod" ]; then
  printf '%s\\n' "$payload" | kubectl -n ${target.namespace} exec -i "$pod" -- bin/kafka-console-producer.sh --bootstrap-server ${kafka.cluster.name}-kafka-bootstrap:${kafka.cluster.listeners.plain.port} --topic ${topic} --command-property acks=all >"$tmp/produce.out" 2>"$tmp/produce.err"
  produce_rc=$?
  if [ "$produce_rc" -eq 0 ]; then
    timeout ${kafka.validation.timeoutSeconds} kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-console-consumer.sh --bootstrap-server ${kafka.cluster.name}-kafka-bootstrap:${kafka.cluster.listeners.plain.port} --topic ${topic} --from-beginning --timeout-ms ${kafka.validation.timeoutSeconds * 1000} >"$tmp/consume.raw" 2>"$tmp/consume.err" || true
    grep -F "$payload" "$tmp/consume.raw" >"$tmp/consume.out" 2>>"$tmp/consume.err"
    consume_rc=$?
  else
    consume_rc=1
    printf '%s\\n' 'producer failed; consumer skipped' >"$tmp/consume.err"
  fi
else
  produce_rc=1
  consume_rc=1
  printf '%s\\n' 'kafka pod not found' >"$tmp/produce.err"
  printf '%s\\n' 'kafka pod not found' >"$tmp/consume.err"
fi
python3 - "$tmp" "$pod" "$payload" "$produce_rc" "$consume_rc" <<'PY'
import hashlib, json, os, sys
tmp, pod, payload = sys.argv[1], sys.argv[2], sys.argv[3]
produce_rc, consume_rc = int(sys.argv[4]), int(sys.argv[5])
def text(name, limit=1200):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
payload_obj = {
    "ok": produce_rc == 0 and consume_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "topic": "${topic}",
    "pod": pod or None,
    "message": {
        "sha256": hashlib.sha256(payload.encode()).hexdigest(),
        "matched": consume_rc == 0,
        "valuesPrinted": False
    },
    "steps": {
        "produce": {"exitCode": produce_rc, "stdoutTail": text("produce.out"), "stderrTail": text("produce.err")},
        "consume": {
            "exitCode": consume_rc,
            "stdoutTail": "payload matched; stdout redacted" if consume_rc == 0 else "payload not found; stdout redacted",
            "stderrTail": text("consume.err"),
        },
    },
    "valuesPrinted": False,
}
print(json.dumps(payload_obj, ensure_ascii=False, indent=2))
sys.exit(0 if payload_obj["ok"] else 1)
PY
`;
}

function topicsScript(kafka: PlatformKafkaConfig, target: KafkaTarget): string {
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name},strimzi.io/kind=Kafka -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
if [ -n "$pod" ]; then
  kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-topics.sh --bootstrap-server ${brokerBootstrap(kafka)} --describe >"$tmp/topics.out" 2>"$tmp/topics.err"
  topics_rc=$?
else
  topics_rc=1
  printf '%s\\n' 'kafka broker pod not found' >"$tmp/topics.err"
  : >"$tmp/topics.out"
fi
python3 - "$tmp" "$pod" "$topics_rc" <<'PY'
import json, os, re, sys
tmp, pod, rc_text = sys.argv[1], sys.argv[2], sys.argv[3]
configured = ${JSON.stringify(kafka.topics.map((topic) => topic.name))}
def text(name, limit=1600):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
topics = {}
for raw in text("topics.out", 200000).splitlines():
    line = raw.strip()
    if not line.startswith("Topic:"):
        continue
    parts = [part.strip() for part in line.split("\\t") if part.strip()]
    data = {}
    for part in parts:
        if ":" in part:
            key, value = part.split(":", 1)
            data[key.strip()] = value.strip()
    name = data.get("Topic")
    if not name or name == "__consumer_offsets":
        continue
    topic = topics.setdefault(name, {"name": name, "partitions": [], "configured": name in configured})
    if "PartitionCount" in data:
        topic["partitionCount"] = int(data.get("PartitionCount") or 0)
        topic["replicationFactor"] = int(data.get("ReplicationFactor") or 0)
        topic["configs"] = data.get("Configs") or ""
    if "Partition" in data:
        topic["partitions"].append({
            "partition": int(data.get("Partition") or 0),
            "leader": data.get("Leader"),
            "replicas": [item for item in re.split(r",\\s*", data.get("Replicas") or "") if item],
            "isr": [item for item in re.split(r",\\s*", data.get("Isr") or "") if item],
        })
for name in configured:
    topics.setdefault(name, {"name": name, "partitions": [], "configured": True, "missing": True})
payload = {
    "ok": int(rc_text) == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "pod": pod or None,
    "topics": sorted(topics.values(), key=lambda item: item["name"]),
    "valuesPrinted": False,
    "stderrTail": text("topics.err"),
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function groupsScript(kafka: PlatformKafkaConfig, target: KafkaTarget): string {
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name},strimzi.io/kind=Kafka -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
if [ -n "$pod" ]; then
  kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-consumer-groups.sh --bootstrap-server ${brokerBootstrap(kafka)} --list >"$tmp/groups.out" 2>"$tmp/groups.err"
  groups_rc=$?
else
  groups_rc=1
  printf '%s\\n' 'kafka broker pod not found' >"$tmp/groups.err"
  : >"$tmp/groups.out"
fi
python3 - "$tmp" "$pod" "$groups_rc" <<'PY'
import json, os, sys
tmp, pod, rc_text = sys.argv[1], sys.argv[2], sys.argv[3]
def text(name, limit=1600):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
groups = [line.strip() for line in text("groups.out", 200000).splitlines() if line.strip()]
payload = {
    "ok": int(rc_text) == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "pod": pod or None,
    "groups": sorted(groups),
    "valuesPrinted": False,
    "stderrTail": text("groups.err"),
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function offsetsScript(kafka: PlatformKafkaConfig, target: KafkaTarget, topic: string | null, group: string | null): string {
  const topics = topic === null ? kafka.topics.map((item) => item.name) : [topic];
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name},strimzi.io/kind=Kafka -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
topics='${JSON.stringify(topics)}'
if [ -n "$pod" ]; then
  python3 - "$topics" <<'PY' >"$tmp/topic-list"
import json, sys
for item in json.loads(sys.argv[1]):
    print(item)
PY
  offsets_rc=0
  : >"$tmp/offsets.out"
  : >"$tmp/offsets.err"
  while IFS= read -r topic_name; do
    kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-get-offsets.sh --bootstrap-server ${brokerBootstrap(kafka)} --topic "$topic_name" >>"$tmp/offsets.out" 2>>"$tmp/offsets.err" || offsets_rc=$?
  done <"$tmp/topic-list"
  if [ ${group === null ? "0" : "1"} -eq 1 ]; then
    kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-consumer-groups.sh --bootstrap-server ${brokerBootstrap(kafka)} --describe --group ${shQuote(group ?? "")} >"$tmp/group.out" 2>"$tmp/group.err" || group_rc=$?
    group_rc=\${group_rc:-0}
  else
    group_rc=0
    : >"$tmp/group.out"
    : >"$tmp/group.err"
  fi
else
  offsets_rc=1
  group_rc=1
  printf '%s\\n' 'kafka broker pod not found' >"$tmp/offsets.err"
  : >"$tmp/offsets.out" >"$tmp/group.out" >"$tmp/group.err"
fi
python3 - "$tmp" "$pod" "$offsets_rc" "$group_rc" <<'PY'
import json, os, sys
tmp, pod, offsets_rc, group_rc = sys.argv[1], sys.argv[2], int(sys.argv[3]), int(sys.argv[4])
def text(name, limit=2000):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
offsets = []
for line in text("offsets.out", 200000).splitlines():
    parts = line.strip().split(":")
    if len(parts) != 3:
        continue
    offsets.append({"topic": parts[0], "partition": int(parts[1]), "endOffset": int(parts[2])})
group_rows = []
for raw in text("group.out", 200000).splitlines():
    line = raw.strip()
    if not line or line.startswith("GROUP") or line.startswith("Consumer group"):
        continue
    cols = line.split()
    if len(cols) >= 6 and cols[1] != "-":
        try:
            group_rows.append({"group": cols[0], "topic": cols[1], "partition": int(cols[2]), "currentOffset": int(cols[3]), "logEndOffset": int(cols[4]), "lag": int(cols[5])})
        except ValueError:
            pass
payload = {
    "ok": offsets_rc == 0 and group_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "pod": pod or None,
    "topicFilter": ${pythonJsonExpr(topic)},
    "groupFilter": ${pythonJsonExpr(group)},
    "offsets": sorted(offsets, key=lambda item: (item["topic"], item["partition"])),
    "groupOffsets": group_rows,
    "valuesPrinted": False,
    "stderrTail": (text("offsets.err") + text("group.err"))[-2000:],
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function tailScript(kafka: PlatformKafkaConfig, target: KafkaTarget, topic: string, limit: number): string {
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name},strimzi.io/kind=Kafka -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
if [ -n "$pod" ]; then
  kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-get-offsets.sh --bootstrap-server ${brokerBootstrap(kafka)} --topic ${shQuote(topic)} >"$tmp/offsets.out" 2>"$tmp/offsets.err"
  offsets_rc=$?
  tail_rc=0
  : >"$tmp/messages.raw"
  while IFS=: read -r topic_name partition end_offset; do
    case "$partition" in ''|*[!0-9]*) continue ;; esac
    case "$end_offset" in ''|*[!0-9]*) continue ;; esac
    start=$(( end_offset > ${limit} ? end_offset - ${limit} : 0 ))
    count=$(( end_offset - start ))
    if [ "$count" -gt 0 ]; then
      timeout ${Math.min(kafka.validation.timeoutSeconds, 20)} kubectl -n ${target.namespace} exec "$pod" -- bin/kafka-console-consumer.sh --bootstrap-server ${brokerBootstrap(kafka)} --topic ${shQuote(topic)} --partition "$partition" --offset "$start" --max-messages "$count" >>"$tmp/messages.raw" 2>>"$tmp/messages.err" || true
    fi
  done <"$tmp/offsets.out"
else
  offsets_rc=1
  tail_rc=1
  printf '%s\\n' 'kafka broker pod not found' >"$tmp/offsets.err"
  : >"$tmp/offsets.out" >"$tmp/messages.raw" >"$tmp/messages.err"
fi
python3 - "$tmp" "$pod" "$offsets_rc" "$tail_rc" <<'PY'
import hashlib, json, os, sys
tmp, pod, offsets_rc, tail_rc = sys.argv[1], sys.argv[2], int(sys.argv[3]), int(sys.argv[4])
def text(name, limit=2000):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
offsets = []
for line in text("offsets.out", 200000).splitlines():
    parts = line.strip().split(":")
    if len(parts) == 3:
        offsets.append({"topic": parts[0], "partition": int(parts[1]), "endOffset": int(parts[2])})
messages = []
for index, line in enumerate(text("messages.raw", 200000).splitlines()):
    encoded = line.encode()
    messages.append({"index": index, "sha256": hashlib.sha256(encoded).hexdigest(), "bytes": len(encoded), "valuePrinted": False})
payload = {
    "ok": offsets_rc == 0 and tail_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "pod": pod or None,
    "topic": "${topic}",
    "limit": ${limit},
    "offsets": offsets,
    "messages": messages[-${limit}:],
    "valuesPrinted": False,
    "stderrTail": (text("offsets.err") + text("messages.err"))[-2000:],
}
print(json.dumps(payload, ensure_ascii=False, indent=2))
sys.exit(0 if payload["ok"] else 1)
PY
`;
}

function produceScript(kafka: PlatformKafkaConfig, target: KafkaTarget, topic: string, key: string | null, payload: string): string {
  const keyValue = key ?? `${kafka.management.diagnosticProducerId}-${Date.now()}`;
  const separator = "|";
  if (keyValue.includes(separator) || keyValue.includes("\n")) throw new Error("kafka produce --key must not contain | or newline");
  return `
set -u
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
pod="$(kubectl -n ${target.namespace} get pod -l strimzi.io/cluster=${kafka.cluster.name},strimzi.io/kind=Kafka -o jsonpath='{.items[0].metadata.name}' 2>"$tmp/pod.err" || true)"
cat >"$tmp/payload.json" <<'UNIDESK_KAFKA_SHADOW_PAYLOAD'
${payload}
UNIDESK_KAFKA_SHADOW_PAYLOAD
printf '%s' ${shQuote(keyValue)} >"$tmp/key.txt"
if [ -n "$pod" ]; then
  printf '%s%s%s\\n' "$(cat "$tmp/key.txt")" ${shQuote(separator)} "$(cat "$tmp/payload.json")" | kubectl -n ${target.namespace} exec -i "$pod" -- bin/kafka-console-producer.sh --bootstrap-server ${brokerBootstrap(kafka)} --topic ${shQuote(topic)} --reader-property parse.key=true --reader-property key.separator=${shQuote(separator)} --command-property acks=all >"$tmp/produce.out" 2>"$tmp/produce.err"
  produce_rc=$?
else
  produce_rc=1
  printf '%s\\n' 'kafka broker pod not found' >"$tmp/produce.err"
  : >"$tmp/produce.out"
fi
python3 - "$tmp" "$pod" "$produce_rc" <<'PY'
import hashlib, json, os, sys
tmp, pod, produce_rc = sys.argv[1], sys.argv[2], int(sys.argv[3])
def text(name, limit=1200):
    try:
        return open(os.path.join(tmp, name), encoding="utf-8", errors="replace").read()[-limit:]
    except FileNotFoundError:
        return ""
payload = open(os.path.join(tmp, "payload.json"), encoding="utf-8").read()
key = open(os.path.join(tmp, "key.txt"), encoding="utf-8").read()
payload_obj = {
    "ok": produce_rc == 0,
    "target": "${target.id}",
    "namespace": "${target.namespace}",
    "cluster": "${kafka.cluster.name}",
    "topic": "${topic}",
    "pod": pod or None,
    "keySha256": hashlib.sha256(key.encode()).hexdigest(),
    "message": {
        "sha256": hashlib.sha256(payload.encode()).hexdigest(),
        "bytes": len(payload.encode()),
        "valuesPrinted": False,
    },
    "producer": "${kafka.management.diagnosticProducerId}",
    "mode": "diagnostic-produce",
    "consume": {"enabled": True, "performed": False},
    "steps": {"produce": {"exitCode": produce_rc, "stdoutTail": text("produce.out"), "stderrTail": text("produce.err")}},
    "valuesPrinted": False,
}
print(json.dumps(payload_obj, ensure_ascii=False, indent=2))
sys.exit(0 if payload_obj["ok"] else 1)
PY
`;
}

function configSummary(kafka: PlatformKafkaConfig, target: KafkaTarget): Record<string, unknown> {
  return {
    configPath: configLabel,
    spec: kafka.metadata.spec,
    target: targetSummary(target),
    switch: kafka.defaults.switch,
    operator: operatorSummary(kafka, target),
    cluster: clusterSummary(kafka, target),
    topics: kafka.topics.map((topic) => topicSummary(topic)),
    clients: kafka.clients.map((client) => clientSummary(client)),
    management: kafka.management,
  };
}

function compactConfigSummary(kafka: PlatformKafkaConfig, target: KafkaTarget): Record<string, unknown> {
  return {
    configPath: configLabel,
    spec: kafka.metadata.spec,
    target: targetSummary(target),
    switch: kafka.defaults.switch,
    operator: {
      implementation: kafka.operator.implementation,
      version: kafka.operator.version,
      deploymentName: kafka.operator.deploymentName,
      resources: kafka.operator.resources,
    },
    cluster: {
      name: kafka.cluster.name,
      bootstrap: bootstrapService(kafka, target),
      replicas: kafka.cluster.replicas,
      storageSize: kafka.cluster.storage.size,
      resources: kafka.cluster.resources,
      jvmOptions: kafka.cluster.jvmOptions,
      entityOperator: kafka.cluster.entityOperator,
      authorizationEnabled: kafka.cluster.authorization.enabled,
    },
    topicCount: kafka.topics.length,
    clientCount: kafka.clients.length,
    management: {
      defaultTopic: kafka.management.defaultTopic,
      defaultTailLimit: kafka.management.defaultTailLimit,
      maxTailLimit: kafka.management.maxTailLimit,
      defaultGroupListLimit: kafka.management.defaultGroupListLimit,
      maxGroupListLimit: kafka.management.maxGroupListLimit,
      consumerGroupCleanup: kafka.management.consumerGroupCleanup,
      diagnosticProducerId: kafka.management.diagnosticProducerId,
    },
    valuesPrinted: false,
  };
}

function targetSummary(target: KafkaTarget): Record<string, unknown> {
  return {
    id: target.id,
    route: target.route,
    namespace: target.namespace,
    role: target.role,
    createNamespace: target.createNamespace,
    storageClassName: target.storageClassName,
  };
}

function operatorSummary(kafka: PlatformKafkaConfig, target: KafkaTarget): Record<string, unknown> {
  return {
    implementation: kafka.operator.implementation,
    version: kafka.operator.version,
    manifestUrl: kafka.operator.manifestUrl,
    deploymentName: kafka.operator.deploymentName,
    namespace: target.namespace,
    crds: kafka.operator.crds,
    resources: kafka.operator.resources,
  };
}

function clusterSummary(kafka: PlatformKafkaConfig, target: KafkaTarget): Record<string, unknown> {
  return {
    name: kafka.cluster.name,
    nodePoolName: kafka.cluster.nodePoolName,
    kafkaVersion: kafka.cluster.kafkaVersion,
    metadataVersion: kafka.cluster.metadataVersion,
    replicas: kafka.cluster.replicas,
    resources: kafka.cluster.resources,
    jvmOptions: kafka.cluster.jvmOptions,
    entityOperator: kafka.cluster.entityOperator,
    storage: { ...kafka.cluster.storage, storageClassName: target.storageClassName },
    bootstrap: bootstrapService(kafka, target),
    authorization: kafka.cluster.authorization,
  };
}

function topicSummary(topic: KafkaTopicSpec): Record<string, unknown> {
  return {
    name: topic.name,
    resourceName: topicResourceName(topic.name),
    partitions: topic.partitions,
    replicas: topic.replicas,
    retentionMs: topic.retentionMs,
    cleanupPolicy: topic.cleanupPolicy,
  };
}

function clientSummary(client: KafkaClientSpec): Record<string, unknown> {
  return {
    id: client.id,
    namespace: client.namespace,
    serviceAccountName: client.serviceAccountName,
    kafkaUserName: client.kafkaUserName,
    secretName: client.secretName,
    produceTopics: client.produceTopics,
    consumeTopics: client.consumeTopics,
    dlqTopics: client.dlqTopics,
    valuesPrinted: false,
  };
}

function policyChecks(kafka: PlatformKafkaConfig, target: KafkaTarget, manifest: string): Array<Record<string, unknown>> {
  return [
    { name: "yaml-source-of-truth", ok: true, detail: "Kafka target, namespace, Strimzi version, topics, clients, storage and switch are read from config/platform-infra/kafka.yaml." },
    { name: "namespace-is-platform-infra", ok: target.namespace === "platform-infra", detail: "Kafka runtime belongs to platform-infra, not an HWLAB or AgentRun lane namespace." },
    { name: "no-public-exposure", ok: !/^\s*type:\s*(NodePort|LoadBalancer)\s*$/mu.test(manifest) && !/^\s*kind:\s*Ingress\s*$/mu.test(manifest), detail: "Kafka POC is ClusterIP/internal only." },
    { name: "single-broker-poc", ok: kafka.cluster.replicas === 1, detail: "The target-scoped POC uses one KRaft broker/controller; production HA remains out of scope." },
    { name: "allow-all-network-policy", ok: manifest.includes("kind: NetworkPolicy") && manifest.includes("name: allow-all") && manifest.includes(`namespace: ${target.namespace}`), detail: `NetworkPolicy/allow-all is rendered in ${target.namespace}.` },
    { name: "durable-produce-enabled", ok: kafka.defaults.switch.produceEnabled === true, detail: "Transactional outbox relays may publish durable application events." },
    { name: "durable-event-stream-mode", ok: kafka.defaults.switch.appIntegrationEnabled === true && kafka.defaults.switch.mode === "durable-event-stream", detail: "Application integration uses the durable event stream contract." },
    { name: "fixed-group-consume-enabled", ok: kafka.defaults.switch.consumeEnabled === true, detail: "Durable projector consumers are enabled." },
    { name: "bounded-kafka-memory", ok: manifest.includes(`"-Xmx": ${kafka.cluster.jvmOptions.xmx}`) && manifest.includes(`memory: ${kafka.cluster.resources.limits.memory}`), detail: "Kafka and Entity Operator JVM/resource budgets are rendered from the owning YAML." },
    { name: "prefix-scoped-group-retention", ok: !kafka.management.consumerGroupCleanup.automatic.enabled || manifest.includes("kind: CronJob") && kafka.management.consumerGroupCleanup.policies.filter((item) => item.automatic).every((item) => manifest.includes(`unidesk.ai/kafka-group-policy: ${item.id}`)), detail: "Automatic cleanup only renders for explicitly selected prefix/pattern/state/age policies." },
  ];
}

function statusSummary(payload: Record<string, unknown>): Record<string, unknown> {
  return {
    ready: payload.ready === true,
    target: payload.target,
    route: payload.route,
    namespace: payload.namespace,
    operator: payload.operator,
    cluster: payload.cluster,
    crdsReady: payload.crdsReady === true,
    nodePoolReady: payload.nodePoolReady === true,
    retentionReady: payload.retentionReady === true,
    podsReady: payload.podsReady === true,
    retention: Array.isArray(payload.retention) ? payload.retention : [],
    topics: Array.isArray(payload.topics) ? payload.topics : [],
    users: Array.isArray(payload.users) ? payload.users : [],
    pods: Array.isArray(payload.pods) ? payload.pods : [],
    services: Array.isArray(payload.services) ? payload.services : [],
    clientSecrets: Array.isArray(payload.clientSecrets) ? payload.clientSecrets : [],
    valuesPrinted: false,
  };
}

function manifestObjectSummary(yaml: string): Array<Record<string, unknown>> {
  const objects: Array<Record<string, unknown>> = [];
  for (const doc of yaml.split(/^---$/mu)) {
    const kind = doc.match(/^\s*kind:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1];
    const name = doc.match(/^\s*name:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1];
    const namespace = doc.match(/^\s*namespace:\s*([A-Za-z0-9._-]+)\s*$/mu)?.[1] ?? null;
    if (kind !== undefined && name !== undefined) objects.push({ kind, name, namespace });
  }
  return objects;
}

function renderPlan(result: Record<string, unknown>): RenderedCliResult {
  const config = record(result.config);
  const target = record(config.target);
  const cluster = record(config.cluster);
  const operator = record(config.operator);
  const switchRecord = record(config.switch);
  const policy = arrayRecords(result.policy);
  const failed = policy.filter((item) => item.ok === false);
  const next = record(result.next);
  return rendered(result, "platform-infra kafka plan", [
    "PLATFORM-INFRA KAFKA PLAN",
    ...table(["FIELD", "VALUE", "DETAIL", "VALUE"], [
      ["TARGET", stringValue(target.id), "route", stringValue(target.route)],
      ["NAMESPACE", stringValue(target.namespace), "role", stringValue(target.role)],
      ["OPERATOR", `strimzi ${stringValue(operator.version)}`, "manifest", stringValue(operator.manifestUrl)],
      ["CLUSTER", stringValue(cluster.name), "bootstrap", stringValue(cluster.bootstrap)],
      ["STORAGE", `${stringValue(record(cluster.storage).size)} ${stringValue(record(cluster.storage).storageClassName)}`, "replicas", stringValue(cluster.replicas)],
      ["TOPICS", String(arrayRecords(config.topics).length), "clients", String(arrayRecords(config.clients).length)],
      ["SWITCH", stringValue(switchRecord.mode), "appIntegration", boolText(switchRecord.appIntegrationEnabled)],
      ["POLICY", failed.length === 0 ? "ok" : `failed=${failed.length}`, "valuesPrinted", "false"],
    ]),
    "",
    "NEXT",
    `  dry-run: ${stringValue(next.dryRun)}`,
    `  apply: ${stringValue(next.apply)}`,
    `  status: ${stringValue(next.status)}`,
    `  validate: ${stringValue(next.validate)}`,
    "",
    "Boundary: Kafka runtime is platform-infra only; durable event production and fixed-group projector consumption are enabled.",
    "Disclosure: Secret values are not printed; client entries show only object/key metadata.",
  ]);
}

function renderApply(result: Record<string, unknown>): RenderedCliResult {
  const target = record(result.target);
  const remote = record(result.remote);
  const steps = record(remote.steps);
  const rows = ["namespace", "operatorApply", "crdPresent", "kafkaApply"].map((name) => {
    const step = record(steps[name]);
    return [name, stringValue(step.exitCode), stringValue(step.stderrTail, "-").trim().slice(-240) || "-"];
  });
  const next = record(result.next);
  return rendered(result, "platform-infra kafka apply", [
    "PLATFORM-INFRA KAFKA APPLY",
    ...table(["TARGET", "NAMESPACE", "MODE", "OK"], [[stringValue(target.id), stringValue(target.namespace), stringValue(result.mode), boolText(result.ok)]]),
    "",
    ...table(["STEP", "EXIT", "ERROR_TAIL"], rows),
    "",
    `NEXT  ${result.ok === true ? stringValue(next.status) : `bun scripts/cli.ts platform-infra kafka apply --target ${stringValue(target.id)} --dry-run --raw`}`,
    "Boundary: the owning YAML is rendered through the controlled server-side apply path; dry-run does not mutate the runtime.",
  ]);
}

function renderStatus(result: Record<string, unknown>): RenderedCliResult {
  const summary = record(result.summary);
  const cluster = record(summary.cluster);
  const operator = record(summary.operator);
  const topics = arrayRecords(summary.topics).map((topic) => [stringValue(topic.topicName), boolText(topic.ready), stringValue(topic.resource)]);
  const users = arrayRecords(summary.users).map((user) => [stringValue(user.name), boolText(user.ready), stringValue(user.secret)]);
  const pods = arrayRecords(summary.pods).map((pod) => [stringValue(pod.name), stringValue(pod.phase), boolText(pod.ready)]);
  const retention = arrayRecords(summary.retention).map((job) => [stringValue(job.name), stringValue(job.schedule), boolText(!job.suspended), stringValue(job.active, "0"), stringValue(job.lastSuccessfulTime)]);
  return rendered(result, "platform-infra kafka status", [
    "PLATFORM-INFRA KAFKA STATUS",
    ...table(["TARGET", "ROUTE", "NAMESPACE", "READY"], [[stringValue(summary.target), stringValue(summary.route), stringValue(summary.namespace), boolText(summary.ready)]]),
    "",
    "CONTROL",
    ...table(["CHECK", "VALUE", "DETAIL"], [
      ["crds", boolText(summary.crdsReady), "Strimzi Kafka CRDs"],
      ["operator", boolText(operator.ready), `${stringValue(operator.name)} ${stringValue(operator.available)}/${stringValue(operator.desired)}`],
      ["cluster", boolText(record(cluster).ready), stringValue(record(cluster).bootstrap)],
      ["nodePool", boolText(summary.nodePoolReady), "dual-role broker/controller"],
      ["groupRetention", boolText(summary.retentionReady), `${retention.length} YAML-owned CronJob(s)`],
      ["pods", boolText(summary.podsReady), `${pods.length} Strimzi workload Pod(s)`],
    ]),
    "",
    "TOPICS",
    ...(topics.length === 0 ? ["-"] : table(["TOPIC", "READY", "RESOURCE"], topics)),
    "",
    "CLIENTS",
    ...(users.length === 0 ? ["-"] : table(["USER", "READY", "SECRET"], users)),
    "",
    "PODS",
    ...(pods.length === 0 ? ["-"] : table(["POD", "PHASE", "READY"], pods)),
    "",
    "GROUP RETENTION",
    ...(retention.length === 0 ? ["-"] : table(["CRONJOB", "SCHEDULE", "ENABLED", "ACTIVE", "LAST_SUCCESS"], retention)),
    ...remoteErrorLines(result),
    "",
    `NEXT  bun scripts/cli.ts platform-infra kafka validate --target ${stringValue(summary.target)}`,
  ]);
}

function renderTopics(result: Record<string, unknown>): RenderedCliResult {
  const query = record(result.query);
  const topics = arrayRecords(query.topics).map((topic) => [
    stringValue(topic.name),
    boolText(topic.configured),
    stringValue(topic.partitionCount, "0"),
    stringValue(topic.replicationFactor, "0"),
    stringValue(topic.configs),
  ]);
  return rendered(result, "platform-infra kafka topics", [
    "PLATFORM-INFRA KAFKA TOPICS",
    ...table(["TARGET", "NAMESPACE", "CLUSTER", "POD"], [[stringValue(query.target), stringValue(query.namespace), stringValue(query.cluster), stringValue(query.pod)]]),
    "",
    ...(topics.length === 0 ? ["TOPICS  -"] : table(["TOPIC", "YAML", "PARTITIONS", "RF", "CONFIGS"], topics)),
    ...remoteErrorLines(result),
    "",
    "Disclosure: message values and Secret values are not printed.",
  ]);
}

function renderGroups(result: Record<string, unknown>): RenderedCliResult {
  const query = record(result.query);
  const presentation = record(result.presentation);
  const limit = Number(presentation.limit);
  const names = Array.isArray(query.groups)
    ? query.groups.flatMap((item) => {
      if (typeof item === "string" && item.length > 0) return [item];
      const value = record(item).name;
      return typeof value === "string" && value.length > 0 ? [value] : [];
    })
    : [];
  const shown = names.slice(0, Number.isInteger(limit) && limit > 0 ? limit : names.length);
  return rendered(result, "platform-infra kafka groups", [
    "PLATFORM-INFRA KAFKA GROUPS",
    ...table(["TARGET", "NAMESPACE", "CLUSTER", "POD"], [[stringValue(query.target), stringValue(query.namespace), stringValue(query.cluster), stringValue(query.pod)]]),
    "",
    ...table(["TOTAL", "SHOWN", "OMITTED"], [[String(names.length), String(shown.length), String(Math.max(0, names.length - shown.length))]]),
    "",
    ...(shown.length === 0 ? ["GROUPS  -"] : table(["GROUP"], shown.map((name) => [name]))),
    ...remoteErrorLines(result),
    ...(names.length > shown.length ? ["", `NEXT  bun scripts/cli.ts platform-infra kafka groups --node ${stringValue(query.target)} --raw`] : []),
  ]);
}

function renderGroupCleanup(result: Record<string, unknown>): RenderedCliResult {
  const cleanup = record(result.cleanup);
  const policy = record(cleanup.policy);
  const summary = record(cleanup.summary);
  const previewLimit = 10;
  const candidateRecords = arrayRecords(cleanup.candidates);
  const deletionRecords = arrayRecords(cleanup.deletions);
  const candidates = candidateRecords.slice(0, previewLimit).map((item) => [stringValue(item.name), stringValue(item.state), stringValue(item.ageHours), stringValue(item.createdAt)]);
  const deletions = deletionRecords.slice(0, previewLimit).map((item) => [stringValue(item.name), stringValue(item.status), stringValue(item.stateAfter)]);
  const next = record(result.next);
  return rendered(result, "platform-infra kafka groups cleanup", [
    "PLATFORM-INFRA KAFKA GROUP CLEANUP",
    ...table(["TARGET", "NAMESPACE", "CLUSTER", "POD", "MODE"], [[stringValue(cleanup.target), stringValue(cleanup.namespace), stringValue(cleanup.cluster), stringValue(cleanup.pod), stringValue(result.mode)]]),
    "",
    "POLICY",
    ...table(["ID", "PREFIX", "INACTIVE", "MIN_AGE_HOURS"], [[stringValue(policy.id), stringValue(policy.prefix), Array.isArray(policy.inactiveStates) ? policy.inactiveStates.join(",") : "-", stringValue(policy.minimumGroupAgeHours)]]),
    "",
    "SELECTION",
    ...table(["TOTAL", "PREFIX", "PATTERN", "INACTIVE", "AGE_OK", "ELIGIBLE", "SELECTED", "OMITTED"], [[stringValue(summary.totalGroupCount, "0"), stringValue(summary.prefixMatchedCount, "0"), stringValue(summary.patternMatchedCount, "0"), stringValue(summary.inactiveMatchedCount, "0"), stringValue(summary.ageEligibleCount, "0"), stringValue(summary.eligibleCount, "0"), stringValue(summary.selectedCount, "0"), stringValue(summary.omittedCount, "0")]]),
    "",
    ...(candidates.length === 0 ? ["CANDIDATES  -"] : table(["GROUP", "STATE", "AGE_HOURS", "CREATED_AT"], candidates)),
    ...(candidateRecords.length > candidates.length ? [`CANDIDATE PREVIEW  ${candidates.length}/${candidateRecords.length}; use --raw for the bounded full selection.`] : []),
    ...(result.mode === "confirmed" ? [
      "",
      "RESULT",
      ...table(["ATTEMPTED", "DELETED", "STATE_CHANGED", "FAILED"], [[stringValue(summary.deleteAttemptedCount, "0"), stringValue(summary.deletedCount, "0"), stringValue(summary.stateChangedCount, "0"), stringValue(summary.failedCount, "0")]]),
      ...(deletions.length === 0 ? [] : ["", ...table(["GROUP", "STATUS", "STATE_AFTER"], deletions)]),
      ...(deletionRecords.length > deletions.length ? [`RESULT PREVIEW  ${deletions.length}/${deletionRecords.length}; use --raw for the bounded full result.`] : []),
    ] : []),
    ...remoteErrorLines(result),
    "",
    `NEXT  ${result.mode === "confirmed" ? stringValue(next.groups) : stringValue(next.confirm)}`,
    "Boundary: only the YAML-selected batch can mutate; prefix, full name pattern, inactive state and minimum group age must all match. --full/--raw never expands the mutation batch.",
  ]);
}

function renderOffsets(result: Record<string, unknown>): RenderedCliResult {
  const query = record(result.query);
  const offsets = arrayRecords(query.offsets).map((item) => [stringValue(item.topic), stringValue(item.partition), stringValue(item.endOffset)]);
  const groupOffsets = arrayRecords(query.groupOffsets).map((item) => [stringValue(item.group), stringValue(item.topic), stringValue(item.partition), stringValue(item.currentOffset), stringValue(item.logEndOffset), stringValue(item.lag)]);
  return rendered(result, "platform-infra kafka offsets", [
    "PLATFORM-INFRA KAFKA OFFSETS",
    ...table(["TARGET", "NAMESPACE", "CLUSTER", "POD"], [[stringValue(query.target), stringValue(query.namespace), stringValue(query.cluster), stringValue(query.pod)]]),
    "",
    "END OFFSETS",
    ...(offsets.length === 0 ? ["-"] : table(["TOPIC", "PARTITION", "END"], offsets)),
    "",
    "GROUP OFFSETS",
    ...(groupOffsets.length === 0 ? ["-"] : table(["GROUP", "TOPIC", "PARTITION", "CURRENT", "END", "LAG"], groupOffsets)),
    ...remoteErrorLines(result),
  ]);
}

function renderTail(result: Record<string, unknown>): RenderedCliResult {
  const query = record(result.query);
  const messages = arrayRecords(query.messages).map((item) => [stringValue(item.index), stringValue(item.sha256), stringValue(item.bytes), boolText(item.valuePrinted)]);
  const offsets = arrayRecords(query.offsets).map((item) => [stringValue(item.partition), stringValue(item.endOffset)]);
  return rendered(result, "platform-infra kafka tail", [
    "PLATFORM-INFRA KAFKA TAIL",
    ...table(["TARGET", "TOPIC", "LIMIT", "POD"], [[stringValue(query.target), stringValue(query.topic), stringValue(query.limit), stringValue(query.pod)]]),
    "",
    "OFFSETS",
    ...(offsets.length === 0 ? ["-"] : table(["PARTITION", "END"], offsets)),
    "",
    "MESSAGES",
    ...(messages.length === 0 ? ["-"] : table(["INDEX", "SHA256", "BYTES", "VALUE_PRINTED"], messages)),
    ...remoteErrorLines(result),
    "",
    "Disclosure: values are hashed only; use application-side replay tools for payload inspection.",
  ]);
}

export function renderKafkaReplay(result: Record<string, unknown>): RenderedCliResult {
  const diagnosis = record(result.diagnosis);
  const rejected = record(diagnosis.rejected);
  const mismatch = record(diagnosis.firstMismatchIdentity);
  return rendered(result, "platform-infra kafka replay agentrun", [
    "PLATFORM-INFRA KAFKA REPLAY",
    ...table(["PLANE", "APPLICATION", "NAMESPACE", "WORKLOAD"], [[stringValue(diagnosis.networkPlane), stringValue(diagnosis.application), stringValue(diagnosis.namespace), stringValue(diagnosis.workload)]]),
    "",
    ...table(["TOPIC", "SCANNED", "ACCEPTED", "PRODUCED", "CLASSIFICATION"], [[stringValue(diagnosis.topic), stringValue(diagnosis.scanned), stringValue(diagnosis.accepted), stringValue(diagnosis.produced), stringValue(rejected.classification)]]),
    "",
    ...table(["MUTATION", "TOPIC_APPENDED", "VALUES_PRINTED"], [[boolText(diagnosis.mutation), boolText(diagnosis.topicAppended), boolText(diagnosis.valuesPrinted)]]),
    ...(diagnosis.firstMismatchIdentity === null ? [] : ["", `MISMATCH  session=${stringValue(mismatch.sessionId)} trace=${stringValue(mismatch.traceId)} reason=${stringValue(mismatch.reason)}`]),
    ...remoteErrorLines(result),
  ]);
}

function remoteErrorLines(result: Record<string, unknown>): string[] {
  if (result.ok !== false) return [];
  const remote = record(result.remote);
  const exitCode = stringValue(remote.exitCode);
  const stderr = stringValue(remote.stderrTail).replace(/\s+/gu, " ").trim().slice(0, 220);
  const stdout = stringValue(remote.stdoutTail).replace(/\s+/gu, " ").trim().slice(0, 220);
  const detail = stderr !== "-" ? stderr : stdout;
  return ["", "ERROR", ...table(["EXIT", "DETAIL"], [[exitCode, detail]])];
}

function rendered(result: Record<string, unknown>, command: string, lines: string[]): RenderedCliResult {
  return { ok: result.ok !== false, command, renderedText: lines.join("\n"), contentType: "text/plain" };
}

function parseApplyOptions(args: string[]): ApplyOptions {
  const commonArgs: string[] = [];
  let confirm = false;
  let dryRun = false;
  let wait = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--confirm") confirm = true;
    else if (arg === "--dry-run") dryRun = true;
    else if (arg === "--wait") wait = true;
    else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  if (confirm && dryRun) throw new Error("kafka apply accepts only one of --confirm or --dry-run");
  return { ...parseCommonOptions(commonArgs), confirm, dryRun: dryRun || !confirm, wait };
}

function parseCommonOptions(args: string[]): CommonOptions {
  let targetId: string | null = null;
  let full = false;
  let raw = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--target" || arg === "--node") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error(`${arg} requires a value`);
      if (!/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error(`${arg} must be a simple target id`);
      targetId = value;
      index += 1;
    } else if (arg === "--full") {
      full = true;
    } else if (arg === "--raw") {
      raw = true;
      full = true;
    } else {
      throw new Error(`unsupported kafka option: ${arg}`);
    }
  }
  return { targetId, full, raw };
}

function parseInspectOptions(args: string[]): KafkaInspectOptions {
  const commonArgs: string[] = [];
  let topic: string | null = null;
  let group: string | null = null;
  let limit: number | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--topic") {
      topic = parseTopicOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--group") {
      group = parseSimpleOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--limit") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--limit requires a value");
      limit = Number(value);
      if (!Number.isInteger(limit) || limit < 1) throw new Error("--limit must be a positive integer");
      index += 1;
    } else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  return { ...parseCommonOptions(commonArgs), topic, group, limit };
}

export function parseKafkaReplayOptions(args: string[]): KafkaReplayOptions {
  const commonArgs: string[] = [];
  let application: string | null = null;
  let sessionId: string | null = null;
  let traceId: string | null = null;
  let lane: string | null = null;
  let limit: number | null = null;
  let timeoutMs: number | null = null;
  let output: KafkaReplayOptions["output"] = "text";
  let noPublish = false;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (!arg.startsWith("--") && application === null) application = arg;
    else if (arg === "--session-id") { sessionId = parseSimpleOption(args[index + 1], arg); index += 1; }
    else if (arg === "--trace-id") { traceId = parseSimpleOption(args[index + 1], arg); index += 1; }
    else if (arg === "--lane") { lane = parseSimpleOption(args[index + 1], arg); index += 1; }
    else if (arg === "--limit") { limit = Number(parseSimpleOption(args[index + 1], arg)); index += 1; }
    else if (arg === "--timeout-ms") { timeoutMs = Number(parseSimpleOption(args[index + 1], arg)); index += 1; }
    else if (arg === "--no-publish" || arg === "--dry-run") noPublish = true;
    else if (arg === "--json") output = "json";
    else if (arg === "-o" || arg === "--output") {
      const value = parseSimpleOption(args[index + 1], arg);
      if (value !== "text" && value !== "json" && value !== "yaml") throw new Error(`${arg} must be text|json|yaml`);
      output = value;
      index += 1;
    } else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") { commonArgs.push(args[index + 1] ?? ""); index += 1; }
    }
  }
  if (application !== "agentrun") throw new Error("Kafka replay requires application 'agentrun'");
  if (sessionId === null) throw new Error("Kafka replay requires --session-id <id>");
  if (!noPublish) throw new Error("Kafka replay currently requires --no-publish; product topic replay is unsupported");
  return { ...parseCommonOptions(commonArgs), sessionId, traceId, lane, limit, timeoutMs, output };
}

function parseGroupCleanupOptions(args: string[]): KafkaGroupCleanupOptions {
  const commonArgs: string[] = [];
  let policyId: string | null = null;
  let confirm = false;
  let limit: number | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--policy") {
      policyId = parseSimpleOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--confirm") {
      confirm = true;
    } else if (arg === "--limit") {
      const value = args[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error("--limit requires a value");
      limit = Number(value);
      if (!Number.isInteger(limit) || limit < 1) throw new Error("--limit must be a positive integer");
      index += 1;
    } else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  if (policyId === null) throw new Error("Kafka consumer group cleanup requires --policy <YAML policy id>");
  return { ...parseCommonOptions(commonArgs), policyId, confirm, limit };
}

async function parseProduceOptions(args: string[]): Promise<KafkaProduceOptions> {
  const commonArgs: string[] = [];
  let topic: string | null = null;
  let key: string | null = null;
  let source = "manual-cli";
  let eventType = "platform-infra.kafka.diagnostic-produce.v1";
  let payload: string | null = null;
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--topic") {
      topic = parseTopicOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--key") {
      key = parseSimpleOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--source") {
      source = parseSimpleOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--event-type") {
      eventType = parseTopicOption(args[index + 1], arg);
      index += 1;
    } else if (arg === "--payload-stdin") {
      payload = await Bun.stdin.text();
    } else {
      commonArgs.push(arg);
      if (arg === "--target" || arg === "--node") {
        commonArgs.push(args[index + 1] ?? "");
        index += 1;
      }
    }
  }
  return { ...parseCommonOptions(commonArgs), topic, key, source, eventType, payload };
}

function bootstrapService(kafka: PlatformKafkaConfig, target: KafkaTarget): string {
  return `${kafka.cluster.name}-kafka-bootstrap.${target.namespace}.svc.cluster.local:${kafka.cluster.listeners.plain.port}`;
}

function brokerBootstrap(kafka: PlatformKafkaConfig): string {
  return `${kafka.cluster.name}-kafka-bootstrap:${kafka.cluster.listeners.plain.port}`;
}

function resolveTopic(kafka: PlatformKafkaConfig, topic: string | null, fallback: string | null): string | null {
  const resolved = topic ?? fallback;
  if (resolved === null) return null;
  if (!kafka.topics.some((item) => item.name === resolved)) throw new Error(`unknown kafka topic ${resolved}; known topics: ${kafka.topics.map((item) => item.name).join(", ")}`);
  return resolved;
}

function boundedLimit(kafka: PlatformKafkaConfig, limit: number | null): number {
  const value = limit ?? kafka.management.defaultTailLimit;
  if (!Number.isInteger(value) || value < 1) throw new Error("limit must be a positive integer");
  if (value > kafka.management.maxTailLimit) throw new Error(`limit ${value} exceeds ${configLabel}.management.maxTailLimit=${kafka.management.maxTailLimit}`);
  return value;
}

function boundedGroupListLimit(kafka: PlatformKafkaConfig, limit: number | null): number {
  const value = limit ?? kafka.management.defaultGroupListLimit;
  if (!Number.isInteger(value) || value < 1) throw new Error("group list limit must be a positive integer");
  if (value > kafka.management.maxGroupListLimit) throw new Error(`limit ${value} exceeds ${configLabel}.management.maxGroupListLimit=${kafka.management.maxGroupListLimit}`);
  return value;
}

function boundedGroupCleanupLimit(kafka: PlatformKafkaConfig, limit: number | null): number {
  const management = kafka.management.consumerGroupCleanup;
  const value = limit ?? management.defaultCandidateLimit;
  if (!Number.isInteger(value) || value < 1) throw new Error("group cleanup candidate limit must be a positive integer");
  if (value > management.maxCandidateLimit) throw new Error(`limit ${value} exceeds ${configLabel}.management.consumerGroupCleanup.maxCandidateLimit=${management.maxCandidateLimit}`);
  return value;
}

function buildDiagnosticPayload(kafka: PlatformKafkaConfig, target: KafkaTarget, options: KafkaProduceOptions, topic: string): string {
  let userPayload: unknown = null;
  if (options.payload !== null) {
    const trimmed = options.payload.trim();
    if (trimmed.length > 0) {
      try {
        userPayload = JSON.parse(trimmed) as unknown;
      } catch {
        userPayload = { textSha256: sha256Hex(trimmed), valuesPrinted: false };
      }
    }
  }
  return JSON.stringify({
    eventId: `evt_${target.id}_${Date.now()}_${Math.random().toString(16).slice(2)}`,
    schemaVersion: 1,
    eventType: options.eventType,
    producer: kafka.management.diagnosticProducerId,
    source: options.source,
    node: target.id,
    namespace: target.namespace,
    topic,
    mode: kafka.defaults.switch.mode,
    appIntegrationEnabled: kafka.defaults.switch.appIntegrationEnabled,
    produceEnabled: kafka.defaults.switch.produceEnabled,
    consumeEnabled: kafka.defaults.switch.consumeEnabled,
    partitionKey: options.key ?? null,
    occurredAt: new Date().toISOString(),
    payload: userPayload ?? {
      kind: "manual-diagnostic-produce",
      spec: kafka.metadata.spec,
      valuesPrinted: false,
    },
    redaction: { valuesPrinted: false },
  });
}

function parseTopicOption(value: string | undefined, optionName: string): string {
  if (value === undefined || value.startsWith("--")) throw new Error(`${optionName} requires a value`);
  if (!/^[A-Za-z0-9._-]+$/u.test(value) || value.includes("..")) throw new Error(`${optionName} has an unsupported Kafka topic/event name`);
  return value;
}

function parseSimpleOption(value: string | undefined, optionName: string): string {
  if (value === undefined || value.startsWith("--")) throw new Error(`${optionName} requires a value`);
  if (!/^[A-Za-z0-9._:/=-]+$/u.test(value)) throw new Error(`${optionName} must be a simple token`);
  return value;
}

function pythonJsonExpr(value: unknown): string {
  return `json.loads(${JSON.stringify(JSON.stringify(value))})`;
}

function topicNameField(record: Record<string, unknown>, key: string, path: string): string {
  const value = y.stringField(record, key, path);
  if (!/^[A-Za-z0-9._-]+$/u.test(value) || value.includes("..")) throw new Error(`${configLabel}.${path}.${key} has an unsupported Kafka topic name`);
  return value;
}

function topicArray(record: Record<string, unknown>, key: string, path: string): string[] {
  return y.stringArrayField(record, key, path).map((value) => {
    if (!/^[A-Za-z0-9._-]+$/u.test(value) || value.includes("..")) throw new Error(`${configLabel}.${path}.${key} contains unsupported topic name ${value}`);
    return value;
  });
}

function topicResourceName(topic: string): string {
  return topic.toLowerCase().replace(/[^a-z0-9-]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 253);
}

function positiveInteger(record: Record<string, unknown>, key: string, path: string): number {
  const value = y.integerField(record, key, path);
  if (value < 1) throw new Error(`${configLabel}.${path}.${key} must be >= 1`);
  return value;
}

function quoteAnnotation(value: string): string {
  return JSON.stringify(value);
}

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

function arrayRecords(value: unknown): Record<string, unknown>[] {
  return Array.isArray(value) ? value.map(record) : [];
}

function stringValue(value: unknown, fallback = "-"): string {
  if (value === undefined || value === null || value === "") return fallback;
  return String(value);
}

function boolText(value: unknown): string {
  return value === true ? "yes" : value === false ? "no" : "-";
}

function table(headers: string[], rows: string[][]): string[] {
  const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0)));
  const renderRow = (row: string[]) => row.map((cell, index) => cell.padEnd(widths[index] ?? cell.length)).join("  ").trimEnd();
  return [renderRow(headers), ...rows.map(renderRow)];
}
