import { displayTimeLabel, formatDisplayDateTime } from "@/config/runtime";
import type { ApiResult, HwpodNodeOpsResponse, HwpodSpecsResponse, LiveProbePayload, LiveSurface, Tone } from "@/types";
import { asRecord, firstNonEmptyString, statusTone } from "@/utils";

export interface ProbeRow {
  key: string;
  label: string;
  method: string;
  path: string;
  status: Tone;
  detail: string;
  lastCheckedAt: string | null;
}

export interface ProbeSummary {
  rows: ProbeRow[];
  tone: Tone;
  okCount: number;
  checkedAt: string | null;
}

export interface BuildRow {
  key: string;
  label: string;
  tag: string | null;
  envImageTag: string | null;
  commitShort: string | null;
  actualCommitShort: string | null;
  envCommitShort: string | null;
  revisionShort: string | null;
  digestShort: string | null;
  builtAt: string | null;
  status: Tone;
  reason: string | null;
  source: string | null;
  rollout: string | null;
}

export interface BuildSummary {
  rows: BuildRow[];
  latest: BuildRow;
  tone: Tone;
  latestText: string;
  countsText: string | null;
}

export interface HwpodDetail {
  key: string;
  title: string;
  body: string;
}

export interface HwpodTile {
  key: string;
  label: string;
  value: string;
  detail: HwpodDetail;
  tone: Tone;
}

export interface HwpodErrorSummary {
  key: string;
  code: string;
  layer: string | null;
  message: string;
  retryable: boolean | null;
}

export interface HwpodNodeOpsSummary {
  status: string;
  tone: Tone;
  contractVersion: string;
  hwpodName: string;
  nodeId: string;
  workspacePath: string;
  caseId: string;
  route: string;
  updatedAt: string | null;
  specsCount: number;
  availableSpecsCount: number;
  supportedOpsCount: number;
  connectedCount: number;
  pendingCount: number;
  tiles: HwpodTile[];
  details: HwpodDetail[];
  errors: HwpodErrorSummary[];
  streamLines: string[];
}

const PROBE_DEFINITIONS = Object.freeze([
  { key: "cloud-api-live", label: "Cloud API 实况身份", method: "GET", path: "/health/live" },
  { key: "cloud-api-health", label: "Cloud API health", method: "GET", path: "/health" },
  { key: "rest-index", label: "REST index", method: "GET", path: "/v1" }
]);

export function summarizeProbeRows(live: LiveSurface | null): ProbeSummary {
  const results = [live?.healthLive, live?.health, live?.restIndex];
  const rows = PROBE_DEFINITIONS.map((definition, index) => rowFromProbe(definition, results[index] ?? null));
  const okCount = rows.filter((row) => row.status === "ok").length;
  const tone: Tone = okCount === rows.length ? "ok" : rows.some((row) => row.status === "blocked" || row.status === "error") ? "blocked" : "pending";
  return { rows, tone, okCount, checkedAt: live?.loadedAt ?? null };
}

export function summarizeBuilds(live: LiveSurface | null): BuildSummary {
  const payload = asRecord(live?.liveBuilds.data);
  const services = recordArray(payload?.services).concat(recordArray(payload?.builds));
  const rows = services.length > 0 ? services.map(rowFromLiveBuildRecord) : [rowFromLiveHealth(live?.healthLive.data ?? null)];
  const explicitLatest = asRecord(payload?.latest);
  const latest = explicitLatest ? rowFromLiveBuildRecord(explicitLatest) : rows.find((row) => row.builtAt) ?? rows[0] ?? emptyBuildRow();
  const tone: Tone = rows.some((row) => row.status === "ok") ? "ok" : rows.some((row) => row.status === "blocked" || row.status === "error") ? "blocked" : rows.some((row) => row.status === "warn") ? "warn" : "pending";
  return { rows, latest, tone, latestText: latestBuildText(latest), countsText: countsText(asRecord(payload?.counts)) };
}

export function summarizeHwpodNodeOps(input: { live?: LiveSurface | null; specs?: HwpodSpecsResponse | null; nodeOps?: HwpodNodeOpsResponse | null; error?: string | null }): HwpodNodeOpsSummary {
  const specPayload = input.live?.hwpodSpecs.data ?? input.specs ?? null;
  const nodePayload = input.live?.hwpodNodeOps.data ?? input.nodeOps ?? null;
  const specs = recordArray(specPayload?.specs);
  const selectedSpec = specs.find((item) => asRecord(item.availability)?.ok === true) ?? specs[0] ?? null;
  const availability = asRecord(selectedSpec?.availability);
  const specResults = recordArray(availability?.results);
  const nodeResults = recordArray(asRecord(nodePayload)?.results);
  const results = specResults.length > 0 ? specResults : nodeResults;
  const websocket = asRecord(asRecord(nodePayload)?.websocket);
  const source = asRecord(selectedSpec?.source);
  const workspace = asRecord(selectedSpec?.workspace);
  const nodeBinding = asRecord(selectedSpec?.nodeBinding);
  const status = firstNonEmptyString(availability?.status, nodePayload?.status, input.live?.hwpodNodeOps.ok ? "ready" : null, input.error ? "blocked" : null) ?? "unknown";
  const contractVersion = firstNonEmptyString(nodePayload?.contractVersion, specPayload?.nodeOpsContractVersion, "hwpod-node-ops-v1") ?? "hwpod-node-ops-v1";
  const hwpodName = firstNonEmptyString(selectedSpec?.name, selectedSpec?.hwpodId, nodePayload?.hwpodId) ?? "未发现";
  const nodeId = firstNonEmptyString(selectedSpec?.nodeId, nodeBinding?.nodeId, nodePayload?.nodeId, asRecord(nodePayload?.requestMeta)?.nodeId) ?? "未发现";
  const workspacePath = firstNonEmptyString(selectedSpec?.workspacePath, workspace?.path) ?? "未发现";
  const caseId = firstNonEmptyString(source?.caseId) ?? "未声明";
  const route = firstNonEmptyString(nodePayload?.route, availability?.nodeOpsRoute, "/v1/hwpod-node-ops") ?? "/v1/hwpod-node-ops";
  const updatedAt = firstNonEmptyString(nodePayload?.observedAt, specPayload?.observedAt, availability?.checkedAt, input.live?.loadedAt);
  const supportedOpsCount = recordArray(nodePayload?.supportedOps).length || stringArray(nodePayload?.supportedOps).length;
  const connectedCount = numberFrom(websocket?.connectedCount, 0);
  const pendingCount = numberFrom(websocket?.pendingCount, 0);
  const specsCount = numberFrom(specPayload?.count, specs.length);
  const availableSpecsCount = numberFrom(specPayload?.availableCount, specs.filter((item) => asRecord(item.availability)?.ok === true).length);
  const errors = collectHwpodErrors(input, availability, results);
  const tone: Tone = errors.length > 0 || statusTone(status) === "blocked" || statusTone(status) === "error" ? "blocked" : statusTone(status) as Tone;
  const details = hwpodDetails({ specPayload, selectedSpec, nodePayload, results });
  const tiles = hwpodTiles({ contractVersion, specsCount, availableSpecsCount, hwpodName, nodeId, supportedOpsCount, results, details, errors, tone });
  return { status, tone, contractVersion, hwpodName, nodeId, workspacePath, caseId, route, updatedAt, specsCount, availableSpecsCount, supportedOpsCount, connectedCount, pendingCount, tiles, details, errors, streamLines: hwpodStreamLines({ selectedSpec, results, errors, websocket, status, hwpodName, nodeId, workspacePath }) };
}

export function formatTimestamp(value: unknown): string {
  const text = firstNonEmptyString(value);
  if (!text) return "未观测";
  const date = new Date(text);
  if (!Number.isFinite(date.getTime())) return text;
  return formatDisplayDateTime(date);
}

export function shortToken(value: unknown, size = 12): string | null {
  const text = firstNonEmptyString(value);
  if (!text) return null;
  return text.length <= size ? text : `${text.slice(0, size)}...`;
}

export function jsonPreview(value: unknown, limit = 2200): string {
  if (value === null || value === undefined) return "null";
  const text = JSON.stringify(value, null, 2) ?? String(value);
  return text.length <= limit ? text : `${text.slice(0, limit)}\n... truncated ${text.length - limit} chars`;
}

function rowFromProbe(definition: { key: string; label: string; method: string; path: string }, probe: ApiResult<LiveProbePayload> | null): ProbeRow {
  const data = probe?.data ?? null;
  const ok = Boolean(probe?.ok) && (data?.ready === true || data?.status === "ok" || data?.status === "ready" || data?.status === "healthy");
  const status: Tone = ok ? "ok" : probe?.ok === false ? probe.status >= 500 || probe.status === 0 ? "blocked" : "warn" : "pending";
  return { ...definition, status, detail: probeDetail(probe, data, definition.path), lastCheckedAt: firstNonEmptyString(data?.observedAt, asRecord(data?.readiness)?.observedAt) };
}

function probeDetail(probe: ApiResult<LiveProbePayload> | null, data: LiveProbePayload | null, path: string): string {
  if (!probe) return `等待 ${path} 实时元数据`;
  if (!probe.ok) return probe.error ?? `${path} HTTP ${probe.status}`;
  if (!data) return `${path} 响应为空`;
  const revision = shortToken(firstNonEmptyString(data.revision, data.commitId), 12);
  const serviceId = firstNonEmptyString(data.serviceId, asRecord(data.service)?.id);
  const ready = data.ready === true ? "ready=true" : "ready=false";
  return `service=${serviceId ?? "unknown"}; env=${firstNonEmptyString(data.environment) ?? "unknown"}; ${ready}; revision=${revision ?? "unknown"}`;
}

function rowFromLiveBuildRecord(record: Record<string, unknown>): BuildRow {
  const build = asRecord(record.build);
  const image = asRecord(record.image);
  const commit = asRecord(record.commit);
  const desiredState = asRecord(record.desiredState);
  const metadata = asRecord(asRecord(build?.liveMetadataMatch)?.metadata);
  const serviceId = firstNonEmptyString(record.serviceId, record.name) ?? "unknown-service";
  const actualCommit = firstNonEmptyString(commit?.id, record.revision);
  const envCommit = firstNonEmptyString(metadata?.commitId, metadata?.revision);
  const builtAt = firstNonEmptyString(build?.createdAt);
  const reason = firstNonEmptyString(build?.unavailableReason, record.reason);
  const tag = firstNonEmptyString(image?.tag);
  return {
    key: serviceId,
    label: serviceId,
    tag,
    envImageTag: firstNonEmptyString(tag, envImageFromSource(build?.source)),
    commitShort: shortToken(actualCommit, 12),
    actualCommitShort: shortToken(actualCommit, 12),
    envCommitShort: shortToken(envCommit, 12),
    revisionShort: shortToken(record.revision, 12),
    digestShort: shortToken(image?.digest, 18),
    builtAt,
    status: builtAt ? "ok" : reason ? "warn" : statusTone(firstNonEmptyString(record.status)) as Tone,
    reason,
    source: sourceLabel(firstNonEmptyString(build?.metadataSource), record.healthUrl),
    rollout: rolloutLabel(desiredState)
  };
}

function rowFromLiveHealth(payload: LiveProbePayload | null): BuildRow {
  const service = asRecord(payload?.service);
  const commit = asRecord(payload?.commit);
  const image = asRecord(payload?.image);
  const build = asRecord(payload?.build);
  const serviceId = firstNonEmptyString(service?.id, payload?.serviceId) ?? "cloud-api";
  const actualCommit = firstNonEmptyString(commit?.id, payload?.revision, payload?.commitId);
  const tag = firstNonEmptyString(image?.tag);
  const builtAt = firstNonEmptyString(build?.createdAt);
  const reason = firstNonEmptyString(build?.unavailableReason);
  return { key: serviceId, label: serviceId, tag, envImageTag: tag, commitShort: shortToken(actualCommit, 12), actualCommitShort: shortToken(actualCommit, 12), envCommitShort: null, revisionShort: shortToken(payload?.revision, 12), digestShort: shortToken(image?.digest, 18), builtAt, status: builtAt ? "ok" : reason ? "warn" : "pending", reason, source: sourceLabel(firstNonEmptyString(build?.metadataSource), "/health/live"), rollout: null };
}

function latestBuildText(row: BuildRow): string {
  const label = displayTimeLabel();
  const time = row.builtAt ? `${formatTimestamp(row.builtAt)} ${label}` : `构建时间不可用（${label}）`;
  return `最新镜像构建时间：${time} · ${row.label} · tag ${row.tag ?? "unknown"} · commit ${row.commitShort ?? "unknown"} · env ${row.envImageTag ?? row.envCommitShort ?? "unknown"} · revision ${row.revisionShort ?? "unknown"}`;
}

function countsText(counts: Record<string, unknown> | null): string | null {
  if (!counts) return null;
  return `服务 ${counts.total ?? "unknown"} 个，可见构建时间 ${counts.withBuildTime ?? "unknown"} 个，缺失 ${counts.unavailable ?? "unknown"} 个，外部 ${counts.external ?? "unknown"} 个`;
}

function emptyBuildRow(): BuildRow {
  return { key: "unknown", label: "unknown-service", tag: null, envImageTag: null, commitShort: null, actualCommitShort: null, envCommitShort: null, revisionShort: null, digestShort: null, builtAt: null, status: "pending", reason: null, source: null, rollout: null };
}

function hwpodDetails(input: { specPayload: HwpodSpecsResponse | null; selectedSpec: Record<string, unknown> | null; nodePayload: HwpodNodeOpsResponse | null; results: Record<string, unknown>[] }): HwpodDetail[] {
  return [
    { key: "contract", title: "Contract", body: jsonPreview(input.nodePayload, 2200) },
    { key: "specs", title: "Specs", body: jsonPreview(input.specPayload, 2600) },
    { key: "spec", title: "Spec", body: jsonPreview(input.selectedSpec, 2600) },
    { key: "node", title: "Node", body: jsonPreview({ selectedSpec: input.selectedSpec, nodeOps: input.nodePayload }, 2600) },
    { key: "ops", title: "Ops", body: jsonPreview(input.results, 2200) },
    { key: "probe", title: "probe", body: jsonPreview({ hwpodSpecs: input.specPayload, hwpodNodeOps: input.nodePayload }, 2600) }
  ];
}

function hwpodTiles(input: { contractVersion: string; specsCount: number; availableSpecsCount: number; hwpodName: string; nodeId: string; supportedOpsCount: number; results: Record<string, unknown>[]; details: HwpodDetail[]; errors: HwpodErrorSummary[]; tone: Tone }): HwpodTile[] {
  const fallbackDetail: HwpodDetail = input.details[0] ?? { key: "probe", title: "probe", body: "null" };
  const detail = (key: string): HwpodDetail => input.details.find((item) => item.key === key) ?? fallbackDetail;
  const tiles: HwpodTile[] = [
    { key: "contract", label: "Contract", value: input.contractVersion, detail: detail("contract"), tone: input.tone },
    { key: "specs", label: "Specs", value: `${input.availableSpecsCount}/${input.specsCount}`, detail: detail("specs"), tone: input.availableSpecsCount > 0 ? "ok" : "blocked" },
    { key: "spec", label: "Spec", value: input.hwpodName, detail: detail("spec"), tone: input.tone },
    { key: "node", label: "Node", value: input.nodeId, detail: detail("node"), tone: input.tone },
    { key: "ops", label: "Ops", value: String(input.results.length || input.supportedOpsCount), detail: detail("ops"), tone: input.errors.length ? "blocked" : "ok" }
  ];
  if (input.results.length > 0) {
    tiles.push(...input.results.map((item, index) => {
      const blocker = asRecord(item.blocker);
      const op = firstNonEmptyString(item.op, item.opId) ?? `op ${index + 1}`;
      const value = item.ok === false ? firstNonEmptyString(blocker?.code, item.status, "blocked") ?? "blocked" : firstNonEmptyString(item.status, "completed") ?? "completed";
      return { key: firstNonEmptyString(item.opId) ?? `op-${index + 1}`, label: op, value, tone: item.ok === false ? "blocked" : statusTone(value) as Tone, detail: { key: firstNonEmptyString(item.opId) ?? `op-${index + 1}`, title: op, body: jsonPreview(item, 1800) } };
    }));
  } else {
    tiles.push({ key: "probe", label: "probe", value: input.errors[0]?.code ?? "等待结果", detail: detail("probe"), tone: input.errors.length ? "blocked" : "pending" });
  }
  return tiles;
}

function hwpodStreamLines(input: { selectedSpec: Record<string, unknown> | null; results: Record<string, unknown>[]; errors: HwpodErrorSummary[]; websocket: Record<string, unknown> | null; status: string; hwpodName: string; nodeId: string; workspacePath: string }): string[] {
  const lines = [`spec ${input.hwpodName} ${input.nodeId} ${input.status} ${input.workspacePath}`.trim()];
  for (const item of input.results) {
    const blocker = asRecord(item.blocker);
    const status = item.ok === false ? firstNonEmptyString(blocker?.code, item.status, "blocked") : firstNonEmptyString(item.status, "completed");
    lines.push(`${firstNonEmptyString(item.opId, "op") ?? "op"} ${firstNonEmptyString(item.op, "unknown") ?? "unknown"} ${status ?? "observed"}`);
  }
  if (input.results.length === 0 && input.websocket) lines.push(`websocket connected=${numberFrom(input.websocket.connectedCount, 0)} pending=${numberFrom(input.websocket.pendingCount, 0)}`);
  for (const error of input.errors) lines.push(`blocked ${error.code} ${error.message}`.trim());
  return uniqueStrings(lines.filter(Boolean));
}

function collectHwpodErrors(input: { live?: LiveSurface | null; error?: string | null }, availability: Record<string, unknown> | null, results: Record<string, unknown>[]): HwpodErrorSummary[] {
  const errors: HwpodErrorSummary[] = [];
  addError(errors, input.error, "store_error");
  addError(errors, input.live?.hwpodSpecs.error, "hwpod_specs_error");
  addError(errors, input.live?.hwpodNodeOps.error, "hwpod_node_ops_error");
  addBlocker(errors, asRecord(availability?.blocker));
  for (const result of results) addBlocker(errors, asRecord(result.blocker));
  return uniqueErrors(errors);
}

function addError(errors: HwpodErrorSummary[], message: unknown, code: string): void {
  const text = firstNonEmptyString(message);
  if (text) errors.push({ key: `${code}:${text}`, code, layer: null, message: text, retryable: null });
}

function addBlocker(errors: HwpodErrorSummary[], blocker: Record<string, unknown> | null): void {
  if (!blocker) return;
  const code = firstNonEmptyString(blocker.code, "blocked") ?? "blocked";
  const message = firstNonEmptyString(blocker.userMessage, blocker.summary, blocker.message, code) ?? code;
  errors.push({ key: `${code}:${message}`, code, layer: firstNonEmptyString(blocker.layer), message, retryable: typeof blocker.retryable === "boolean" ? blocker.retryable : null });
}

function uniqueErrors(errors: HwpodErrorSummary[]): HwpodErrorSummary[] {
  const seen = new Set<string>();
  return errors.filter((error) => {
    if (seen.has(error.key)) return false;
    seen.add(error.key);
    return true;
  });
}

function recordArray(value: unknown): Record<string, unknown>[] {
  return Array.isArray(value) ? value.map((item) => asRecord(item)).filter((item): item is Record<string, unknown> => Boolean(item)) : [];
}

function stringArray(value: unknown): string[] {
  return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string" && item.trim().length > 0) : [];
}

function uniqueStrings(values: string[]): string[] {
  return Array.from(new Set(values));
}

function numberFrom(value: unknown, fallback: number): number {
  const number = Number(value);
  return Number.isFinite(number) ? number : fallback;
}

function envImageFromSource(value: unknown): string | null {
  const text = firstNonEmptyString(value);
  return text?.match(/@env:([^\s/]+)/u)?.[1] ?? null;
}

function sourceLabel(metadataSource: string | null, healthUrl: unknown): string | null {
  const parts = [firstNonEmptyString(healthUrl) ? "live health" : null, metadataSource].filter(Boolean);
  return parts.length ? parts.join(" / ") : null;
}

function rolloutLabel(desiredState: Record<string, unknown> | null): string | null {
  if (!desiredState) return null;
  const replicas = Number(desiredState.replicas);
  return [firstNonEmptyString(desiredState.namespace), firstNonEmptyString(desiredState.profile), Number.isFinite(replicas) ? `${replicas} replicas` : null, firstNonEmptyString(desiredState.source)].filter(Boolean).join(" / ") || null;
}
