import type { RenderedCliResult } from "../output";

export function renderSub2ApiOps(result: Record<string, unknown>): RenderedCliResult {
  const action = String(result.action ?? "platform-infra-sub2api-ops");
  const lines = action.endsWith("diagnosis") ? renderDiagnosis(result) : renderChannels(result);
  return {
    ok: result.ok !== false,
    command: action.replaceAll("-", " "),
    renderedText: lines.join("\n"),
    contentType: "text/plain",
  };
}

function renderDiagnosis(result: Record<string, unknown>): string[] {
  const source = record(result.source);
  const groups = arrayRecords(result.groups);
  const rows = groups.flatMap((group) => arrayRecords(group.diagnoses).map((item) => {
    const metric = record(item.metric);
    return [
      stringValue(item.id),
      stringValue(item.severity).toUpperCase(),
      `${stringValue(metric.value)} ${stringValue(metric.unit)}`.trim(),
      stringValue(item.message),
      `${stringValue(group.groupName)} / ${stringValue(group.platform)}`,
    ];
  }));
  const lines = [
    "PLATFORM-INFRA SUB2API OPS DIAGNOSIS",
    ...table(["ID", "SEVERITY", "VALUE", "DIAGNOSIS", "SCOPE"], rows),
    "",
    "SOURCE",
    ...table(["FIELD", "VALUE"], [
      ["status", stringValue(source.status)],
      ["upstreamVersion", stringValue(source.upstreamVersion)],
      ["metrics", stringValue(source.metricsEndpoint)],
      ["advice", stringValue(source.projectionKind)],
      ["nativeDiagnosisEndpoint", stringValue(record(source.nativeDiagnosisEndpoint).status)],
    ]),
  ];
  const selected = record(result.selectedDiagnosis);
  if (Object.keys(selected).length > 0) {
    const metric = record(selected.metric);
    lines.push(
      "",
      "DETAIL",
      ...table(["FIELD", "VALUE"], [
        ["id", stringValue(selected.id)],
        ["category", stringValue(selected.category)],
        ["severity", stringValue(selected.severity)],
        ["metric", `${stringValue(metric.name)}=${stringValue(metric.value)} ${stringValue(metric.unit)}`.trim()],
        ["impact", stringValue(selected.impact)],
        ["nativeAdvice", stringValue(selected.advice, "-")],
        ["inference", stringValue(selected.inferenceStatus)],
      ]),
    );
    const evidence = record(result.evidence);
    const evidenceRows = arrayRecords(evidence.records).map((item) => [
      stringValue(item.requestId, "-"),
      stringValue(item.createdAt, "-"),
      stringValue(item.accountName, stringValue(item.accountId, "-")),
      stringValue(item.statusCode, "-"),
      stringValue(item.message, "-").replace(/\s+/gu, " ").slice(0, 80),
    ]);
    lines.push("", "RELATED EVIDENCE", ...(evidenceRows.length === 0 ? ["-"] : table(["REQUEST_ID", "AT", "ACCOUNT", "STATUS", "SUMMARY"], evidenceRows)));
  }
  lines.push(
    "",
    "NEXT",
    "  detail: bun scripts/cli.ts platform-infra sub2api ops diagnosis --id <diagnosis-id>",
    "  json: bun scripts/cli.ts platform-infra sub2api ops diagnosis --json",
    "",
    `Evidence boundary: ${stringValue(source.evidenceBoundary)}`,
    "Disclosure: one-shot read-only snapshot; no foreground refresh, Secret, token, or full log output.",
  );
  if (result.error) lines.push(`Error: ${stringValue(result.error)}`);
  return lines;
}

function renderChannels(result: Record<string, unknown>): string[] {
  const source = record(result.source);
  const channels = arrayRecords(result.channels);
  const rows = channels.map((channel) => {
    const primary = record(channel.primary);
    return [
      stringValue(channel.id),
      stringValue(channel.name),
      stringValue(channel.provider),
      stringValue(primary.model),
      stringValue(channel.status),
      stringValue(primary.latencyMs, "-"),
      stringValue(primary.pingLatencyMs, "-"),
      formatAvailability(primary.availability),
      stringValue(channel.recentRecordCount, "0"),
      stringValue(channel.collectedAt, "-"),
    ];
  });
  const lines = [
    "PLATFORM-INFRA SUB2API OPS CHANNELS",
    ...table(["ID", "CHANNEL", "PLATFORM", "MODEL", "STATUS", "LATENCY_MS", "PING_MS", "AVAIL", "RECORDS", "COLLECTED_AT"], rows),
    "",
    "SUMMARY",
    ...table(["FIELD", "VALUE"], [
      ["overallStatus", stringValue(result.overallStatus)],
      ["window", stringValue(record(result.query).window)],
      ["sourceStatus", stringValue(source.status)],
      ["refreshRemaining", stringValue(record(source.refreshRemaining).status)],
    ]),
  ];
  const history = record(result.history);
  const historyRows = arrayRecords(history.records).map((item) => [
    stringValue(item.id),
    stringValue(item.model),
    stringValue(item.status),
    stringValue(item.latencyMs, "-"),
    stringValue(item.pingLatencyMs, "-"),
    stringValue(item.checkedAt, "-"),
  ]);
  if (historyRows.length > 0) {
    lines.push(
      "",
      "PAST → NOW",
      ...table(["ID", "MODEL", "STATUS", "LATENCY_MS", "PING_MS", "CHECKED_AT"], historyRows),
      `pageSize=${stringValue(history.pageSize)} moreAvailable=${stringValue(history.moreAvailable)} nextPageToken=${stringValue(history.nextPageToken)}`,
    );
  }
  const selectedRecord = record(history.selectedRecord);
  if (Object.keys(selectedRecord).length > 0) {
    const timeout = record(selectedRecord.timeout);
    const correlation = record(selectedRecord.correlation);
    const final = record(correlation.final);
    const accounts = arrayRecords(correlation.accounts);
    const failovers = arrayRecords(correlation.failovers);
    const selectFailures = arrayRecords(correlation.selectFailures);
    lines.push(
      "",
      "RECORD",
      ...table(["FIELD", "VALUE"], [
        ["id", stringValue(selectedRecord.id)],
        ["model", stringValue(selectedRecord.model)],
        ["status", stringValue(selectedRecord.status)],
        ["latencyMs", stringValue(selectedRecord.latencyMs)],
        ["pingLatencyMs", stringValue(selectedRecord.pingLatencyMs)],
        ["checkedAt", stringValue(selectedRecord.checkedAt)],
        ["message", stringValue(selectedRecord.message)],
        ["runtimeVersion", stringValue(timeout.runtimeVersion)],
        ["sourceReferenceVersion", stringValue(timeout.sourceReferenceVersion)],
        ["runtimePolicyStatus", stringValue(timeout.runtimePolicyStatus)],
        ["sourceResponseHeaderMs", stringValue(timeout.responseHeaderTimeoutMs)],
        ["sourceTotalRequestMs", stringValue(timeout.totalRequestTimeoutMs)],
        ["remainingAfterHeaderMs", stringValue(timeout.remainingAfterResponseHeaderMs)],
        ["correlationStatus", stringValue(correlation.status)],
        ["requestId", stringValue(correlation.requestId)],
        ["accounts", accounts.map((item) => `${stringValue(item.id)}:${stringValue(item.name)}`).join(",") || "-"],
        ["failoverCount", String(failovers.length)],
        ["selectFailureCount", String(selectFailures.length)],
        ["finalStatus", stringValue(final.statusCode)],
        ["finalLatencyMs", stringValue(final.latencyMs)],
        ["timeoutSufficient", stringValue(correlation.sufficientForObservedCompletion)],
        ["sufficiencyStatus", stringValue(correlation.sufficiencyStatus)],
      ]),
    );
    if (correlation.traceNext) lines.push(`Trace: ${stringValue(correlation.traceNext)}`);
    if (correlation.reason) lines.push(`Correlation: ${stringValue(correlation.reason)}`);
  }
  lines.push(
    "",
    "NEXT",
    "  channel: bun scripts/cli.ts platform-infra sub2api ops channels --channel <id-or-name>",
    "  window: bun scripts/cli.ts platform-infra sub2api ops channels --window 7d|15d|30d",
    "  older page: bun scripts/cli.ts platform-infra sub2api ops channels --channel <id-or-name> --page-token <record-id>",
    "  record: bun scripts/cli.ts platform-infra sub2api ops channels --channel <id-or-name> --record <record-id>",
    "  json: bun scripts/cli.ts platform-infra sub2api ops channels --json",
    "",
    "Disclosure: one-shot read-only snapshot; native response has no refresh countdown, and the CLI does not simulate one.",
  );
  if (result.error) lines.push(`Error: ${stringValue(result.error)}`);
  return lines;
}

function formatAvailability(value: unknown): string {
  return typeof value === "number" && Number.isFinite(value) ? `${value.toFixed(2)}%` : stringValue(value, "-");
}

function table(headers: string[], rows: string[][]): string[] {
  if (rows.length === 0) return ["-"];
  const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => visibleLength(row[index] ?? ""))));
  const format = (row: string[]): string => row.map((cell, index) => `${cell}${" ".repeat(Math.max(0, widths[index]! - visibleLength(cell)))}`).join("  ").trimEnd();
  return [format(headers), format(widths.map((width) => "-".repeat(width))), ...rows.map(format)];
}

function visibleLength(value: string): number {
  return [...value].length;
}

function record(value: unknown): Record<string, unknown> {
  return value !== null && typeof value === "object" && !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 (typeof value === "string") return value.length > 0 ? value : fallback;
  if (typeof value === "number" || typeof value === "boolean") return String(value);
  return fallback;
}
