import type { Sub2ApiOpsOptions } from "./types";

const upstreamVersion = "v0.1.155";
const diagnosisRuleSource = "frontend/src/views/admin/ops/components/OpsDashboardHeader.vue";
const diagnosisTextSource = "frontend/src/i18n/locales/zh/admin/ops.ts";
const channelHistoryPageSize = 20;
const monitorResponseHeaderTimeoutMs = 30_000;
const monitorTotalRequestTimeoutMs = 45_000;

export function projectSub2ApiOps(raw: Record<string, unknown>, options: Sub2ApiOpsOptions): Record<string, unknown> {
  const target = record(raw.target);
  if (raw.ok !== true) {
    return {
      ok: false,
      action: `platform-infra-sub2api-ops-${options.action}`,
      target,
      query: querySummary(options),
      source: sourceSummary(options.action, "unavailable"),
      error: stringValue(raw.error, "Sub2API native source unavailable"),
      valuesPrinted: false,
    };
  }
  const data = record(raw.data);
  return options.action === "diagnosis"
    ? projectDiagnosis(target, data, options)
    : projectChannels(target, data, options);
}

function projectDiagnosis(target: Record<string, unknown>, data: Record<string, unknown>, options: Sub2ApiOpsOptions): Record<string, unknown> {
  const runtimeVersion = record(data.runtimeVersion);
  const groups = arrayRecords(data.groups).map((entry) => {
    const group = record(entry.group);
    const overview = record(entry.overview);
    const scope = group.id === null || group.id === undefined ? "all" : `g${String(group.id)}`;
    return {
      id: scope,
      groupId: group.id ?? null,
      groupName: stringValue(group.name, "all"),
      platform: stringValue(group.platform, "all"),
      window: {
        kind: "native-ops-time-range",
        value: options.timeRange,
        startAt: overview.start_time ?? null,
        endAt: overview.end_time ?? null,
      },
      sourceStatus: "available",
      diagnoses: diagnosisItems(scope, overview),
      metrics: compactOverview(overview),
    };
  });
  const selectedDiagnosis = options.diagnosisId === null
    ? null
    : groups.flatMap((group) => arrayRecords(group.diagnoses)).find((item) => item.id === options.diagnosisId) ?? null;
  return {
    ok: options.diagnosisId === null || selectedDiagnosis !== null,
    action: "platform-infra-sub2api-ops-diagnosis",
    target,
    query: querySummary(options),
    source: sourceSummary("diagnosis", "available", runtimeVersion),
    groups,
    selectedDiagnosis,
    evidence: options.diagnosisId === null ? null : projectEvidence(record(data.evidence)),
    error: options.diagnosisId !== null && selectedDiagnosis === null ? `diagnosis id not found: ${options.diagnosisId}` : null,
    valuesPrinted: false,
  };
}

function diagnosisItems(scope: string, overview: Record<string, unknown>): Record<string, unknown>[] {
  const items: Record<string, unknown>[] = [];
  const qps = numberAt(record(overview.qps).current, 0);
  const errorRate = numberAt(overview.error_rate, 0);
  if (qps === 0 && errorRate === 0) {
    return [diagnosisItem(scope, "idle", "info", "system_activity", 0, "requests/s", "系统当前处于待机状态", "无活跃流量", null, overview)];
  }
  const systemMetrics = record(overview.system_metrics);
  if (systemMetrics.db_ok === false) items.push(diagnosisItem(scope, "db-down", "critical", "db_ok", false, "boolean", "数据库连接失败", "所有数据库操作将失败", "检查数据库服务状态、网络连接和连接配置", overview));
  if (systemMetrics.redis_ok === false) items.push(diagnosisItem(scope, "redis-down", "warning", "redis_ok", false, "boolean", "Redis连接失败", "缓存功能降级，性能可能下降", "检查Redis服务状态和网络连接", overview));
  const cpu = numberAt(systemMetrics.cpu_usage_percent, 0);
  if (cpu > 90) items.push(diagnosisItem(scope, "cpu-critical", "critical", "cpu_usage_percent", cpu, "%", `CPU使用率严重过高 (${cpu.toFixed(1)}%)`, "系统响应变慢，可能影响所有请求", "检查CPU密集型任务，考虑扩容或优化代码", overview));
  else if (cpu > 80) items.push(diagnosisItem(scope, "cpu-high", "warning", "cpu_usage_percent", cpu, "%", `CPU使用率偏高 (${cpu.toFixed(1)}%)`, "系统负载较高，需要关注", "监控CPU趋势，准备扩容方案", overview));
  const memory = numberAt(systemMetrics.memory_usage_percent, 0);
  if (memory > 90) items.push(diagnosisItem(scope, "memory-critical", "critical", "memory_usage_percent", memory, "%", `内存使用率严重过高 (${memory.toFixed(1)}%)`, "可能触发OOM，系统稳定性受威胁", "检查内存泄漏，考虑增加内存或优化内存使用", overview));
  else if (memory > 85) items.push(diagnosisItem(scope, "memory-high", "warning", "memory_usage_percent", memory, "%", `内存使用率偏高 (${memory.toFixed(1)}%)`, "内存压力较大，需要关注", "监控内存趋势，检查是否有内存泄漏", overview));
  const ttft = numberAt(record(overview.ttft).p99_ms, 0);
  if (ttft > 500) items.push(diagnosisItem(scope, "ttft-high", "warning", "ttft.p99_ms", ttft, "ms", `首 Token 时间偏高 (${ttft.toFixed(0)}ms)`, "用户感知时长增加", "优化请求处理流程，减少前置逻辑耗时", overview));
  const upstreamRate = numberAt(overview.upstream_error_rate, 0) * 100;
  if (upstreamRate > 5) items.push(diagnosisItem(scope, "upstream-critical", "critical", "upstream_error_rate", upstreamRate, "%", `上游错误率严重偏高 (${upstreamRate.toFixed(2)}%)`, "可能影响大量用户请求", "检查上游服务健康状态，启用降级策略", overview));
  else if (upstreamRate > 2) items.push(diagnosisItem(scope, "upstream-high", "warning", "upstream_error_rate", upstreamRate, "%", `上游错误率偏高 (${upstreamRate.toFixed(2)}%)`, "建议检查上游服务状态", "联系上游服务团队，准备降级方案", overview));
  const clientRate = errorRate * 100;
  if (clientRate > 3) items.push(diagnosisItem(scope, "error-high", "critical", "error_rate", clientRate, "%", `错误率过高 (${clientRate.toFixed(2)}%)`, "大量请求失败", "查看错误日志，定位错误根因，紧急修复", overview));
  else if (clientRate > 0.5) items.push(diagnosisItem(scope, "error-elevated", "warning", "error_rate", clientRate, "%", `错误率偏高 (${clientRate.toFixed(2)}%)`, "建议检查错误日志", "分析错误类型和分布，制定修复计划", overview));
  const sla = numberAt(overview.sla, 0) * 100;
  if (sla < 90) items.push(diagnosisItem(scope, "sla-critical", "critical", "sla", sla, "%", `SLA 严重低于目标 (${sla.toFixed(2)}%)`, "用户体验严重受损", "紧急排查错误原因，必要时采取限流保护", overview));
  else if (sla < 98) items.push(diagnosisItem(scope, "sla-low", "warning", "sla", sla, "%", `SLA 低于目标 (${sla.toFixed(2)}%)`, "需要关注服务质量", "分析SLA下降原因，优化系统性能", overview));
  const healthScore = finiteNumber(overview.health_score);
  if (healthScore !== null && healthScore < 60) items.push(diagnosisItem(scope, "health-critical", "critical", "health_score", healthScore, "score", `综合健康评分过低 (${healthScore})`, "多个指标可能同时异常，建议优先排查错误与资源使用情况", "全面检查系统状态，优先处理critical级别问题", overview));
  else if (healthScore !== null && healthScore < 90) items.push(diagnosisItem(scope, "health-low", "warning", "health_score", healthScore, "score", `综合健康评分偏低 (${healthScore})`, "可能存在轻度波动，建议关注 SLA 与错误率", "监控指标趋势，预防问题恶化", overview));
  if (items.length === 0) items.push(diagnosisItem(scope, "healthy", "info", "health", "normal", "state", "所有系统指标正常", "服务运行稳定", null, overview));
  return items;
}

function diagnosisItem(scope: string, category: string, severity: string, metric: string, value: unknown, unit: string, message: string, impact: string, advice: string | null, overview: Record<string, unknown>): Record<string, unknown> {
  return {
    id: `${scope}:${category}`,
    category,
    severity,
    message,
    metric: { name: metric, value, unit },
    impact,
    advice,
    adviceKind: advice === null ? null : "native-frontend-advice",
    factRef: `${scope}.metrics`,
    inferenceStatus: "not-verified",
  };
}

function compactOverview(overview: Record<string, unknown>): Record<string, unknown> {
  return {
    requestCount: overview.request_count_total ?? null,
    successCount: overview.success_count ?? null,
    errorCount: overview.error_count_total ?? null,
    errorRate: overview.error_rate ?? null,
    upstreamErrorRate: overview.upstream_error_rate ?? null,
    sla: overview.sla ?? null,
    healthScore: overview.health_score ?? null,
    qps: record(overview.qps).current ?? null,
    ttftP99Ms: record(overview.ttft).p99_ms ?? null,
    collectedAt: overview.end_time ?? null,
  };
}

function projectEvidence(evidence: Record<string, unknown>): Record<string, unknown> | null {
  if (Object.keys(evidence).length === 0) return null;
  const records = arrayRecords(evidence.records).map((item) => ({
    requestId: item.request_id ?? null,
    createdAt: item.created_at ?? null,
    platform: item.platform ?? null,
    model: item.model ?? null,
    accountId: item.account_id ?? null,
    accountName: item.account_name ?? null,
    statusCode: item.status_code ?? item.upstream_status_code ?? null,
    durationMs: item.duration_ms ?? null,
    severity: item.severity ?? null,
    message: item.message ?? null,
  }));
  return { diagnosisId: evidence.diagnosisId ?? null, recordCount: records.length, records };
}

function projectChannels(target: Record<string, unknown>, data: Record<string, unknown>, options: Sub2ApiOpsOptions): Record<string, unknown> {
  const runtimeVersion = record(data.runtimeVersion);
  const channels = arrayRecords(data.channels).map((entry) => projectChannel(entry, options.window));
  const operational = channels.every((channel) => channel.status === "OPERATIONAL");
  const history = arrayRecords(data.history)
    .map((item) => ({
      id: item.id ?? null,
      model: item.model ?? null,
      status: item.status ?? null,
      latencyMs: item.latency_ms ?? null,
      pingLatencyMs: item.ping_latency_ms ?? null,
      message: item.message ?? null,
      checkedAt: item.checked_at ?? null,
    }))
    .sort((left, right) => String(left.checkedAt).localeCompare(String(right.checkedAt)));
  const historyProjection = options.channel === null ? null : paginateHistory(history, options, record(data.correlation), runtimeVersion);
  const historyError = historyProjection === null ? null : historyProjection.error;
  return {
    ok: historyError === null,
    action: "platform-infra-sub2api-ops-channels",
    target,
    query: querySummary(options),
    source: sourceSummary("channels", "available", runtimeVersion),
    timeoutPolicy: monitorTimeoutPolicy(runtimeVersion),
    overallStatus: operational ? "OPERATIONAL" : "DEGRADED",
    channels,
    history: historyProjection,
    error: historyError,
    valuesPrinted: false,
  };
}

function paginateHistory(history: Record<string, unknown>[], options: Sub2ApiOpsOptions, correlation: Record<string, unknown>, runtimeVersion: Record<string, unknown>): Record<string, unknown> {
  if (options.recordId !== null) {
    const selectedRecordRaw = history.find((item) => String(item.id) === options.recordId) ?? null;
    const selectedRecord = selectedRecordRaw === null ? null : projectSelectedRecord(selectedRecordRaw, correlation, runtimeVersion);
    return {
      order: "PAST_TO_NOW",
      pageSize: channelHistoryPageSize,
      sourceRecordCount: history.length,
      sourceCapReached: history.length === 1000,
      records: [],
      moreAvailable: false,
      nextPageToken: null,
      selectedRecord,
      error: selectedRecord === null ? `channel history record not found: ${options.recordId}` : null,
    };
  }
  let end = history.length;
  if (options.pageToken !== null) {
    const cursorIndex = history.findIndex((item) => String(item.id) === options.pageToken);
    if (cursorIndex < 0) {
      return {
        order: "PAST_TO_NOW",
        pageSize: channelHistoryPageSize,
        sourceRecordCount: history.length,
        sourceCapReached: history.length === 1000,
        records: [],
        moreAvailable: false,
        nextPageToken: null,
        selectedRecord: null,
        error: `channel history page token not found: ${options.pageToken}`,
      };
    }
    end = cursorIndex;
  }
  const start = Math.max(0, end - channelHistoryPageSize);
  const records = history.slice(start, end);
  return {
    order: "PAST_TO_NOW",
    pageSize: channelHistoryPageSize,
    sourceRecordCount: history.length,
    sourceCapReached: history.length === 1000,
    records,
    moreAvailable: start > 0,
    nextPageToken: start > 0 && records.length > 0 ? records[0]?.id ?? null : null,
    selectedRecord: null,
    error: null,
  };
}

function projectSelectedRecord(item: Record<string, unknown>, correlation: Record<string, unknown>, runtimeVersion: Record<string, unknown>): Record<string, unknown> {
  const latencyMs = typeof item.latencyMs === "number" ? item.latencyMs : null;
  const selected = record(correlation.selected);
  const final = record(selected.final);
  const failovers = arrayRecords(selected.failovers);
  const selectFailures = arrayRecords(selected.selectFailures);
  const totalLatencyMs = typeof final.latencyMs === "number" ? final.latencyMs : null;
  const runtimeTag = typeof runtimeVersion.version === "string" && runtimeVersion.version.length > 0 ? runtimeVersion.version : null;
  const runtimeVersionMismatch = runtimeTag?.replace(/^v/u, "") !== upstreamVersion.replace(/^v/u, "");
  return {
    ...item,
    timeout: {
      observedKind: String(item.message ?? "").toLowerCase().includes("timeout awaiting response headers") ? "response-header" : "unknown",
      responseHeaderTimeoutMs: monitorResponseHeaderTimeoutMs,
      totalRequestTimeoutMs: monitorTotalRequestTimeoutMs,
      sourceReferenceVersion: upstreamVersion,
      runtimeVersion: runtimeTag,
      runtimeVersionMismatch,
      runtimePolicyStatus: runtimeVersionMismatch ? "unverified" : "source-version-verified",
      remainingAfterResponseHeaderMs: monitorTotalRequestTimeoutMs - monitorResponseHeaderTimeoutMs,
      observedLatencyDeltaMs: latencyMs === null ? null : latencyMs - monitorResponseHeaderTimeoutMs,
      perUpstreamTimeout: { status: "unsupported", reason: "native monitor history does not expose per-upstream timeout" },
      overallGatewayDeadline: { status: "unsupported", reason: "native monitor history does not expose the gateway request deadline" },
      failoverReserve: { status: "unsupported", reason: "native monitor history does not expose a dedicated failover reserve" },
    },
    correlation: {
      status: correlation.status ?? "unsupported",
      reason: correlation.reason ?? null,
      requestId: selected.requestId ?? null,
      match: selected.match ?? null,
      apiKeyName: selected.apiKeyName ?? null,
      model: selected.model ?? null,
      accounts: selected.accounts ?? [],
      upstreamErrors: selected.upstreamErrors ?? [],
      failovers,
      selectFailures,
      final: Object.keys(final).length === 0 ? null : final,
      switchingObserved: failovers.length > 0,
      selectionFailureObserved: selectFailures.length > 0,
      sufficientForObservedCompletion: runtimeVersionMismatch || totalLatencyMs === null ? null : monitorTotalRequestTimeoutMs >= totalLatencyMs,
      sufficiencyStatus: runtimeVersionMismatch ? "unverified-runtime-version-mismatch" : totalLatencyMs === null ? "unsupported-no-final-latency" : "evaluated-against-verified-source-version",
      traceNext: selected.requestId ? `bun scripts/cli.ts platform-infra sub2api codex-pool trace --request-id ${String(selected.requestId)}` : null,
      candidates: correlation.status === "ambiguous" ? correlation.candidates ?? [] : [],
    },
  };
}

function projectChannel(entry: Record<string, unknown>, window: "7d" | "15d" | "30d"): Record<string, unknown> {
  const summary = record(entry.summary);
  const detail = record(entry.detail);
  const models = arrayRecords(detail.models).map((model) => ({
    model: model.model ?? null,
    status: upperStatus(model.latest_status),
    latencyMs: model.latest_latency_ms ?? null,
    availability: availabilityFor(model, window),
    availabilityWindow: window,
    avgLatency7dMs: model.avg_latency_7d_ms ?? null,
  }));
  const timeline = arrayRecords(summary.timeline)
    .map((point) => ({
      status: upperStatus(point.status),
      latencyMs: point.latency_ms ?? null,
      pingLatencyMs: point.ping_latency_ms ?? null,
      checkedAt: point.checked_at ?? null,
    }))
    .sort((left, right) => String(left.checkedAt).localeCompare(String(right.checkedAt)));
  const status = [summary.primary_status, ...arrayRecords(summary.extra_models).map((item) => item.status)]
    .every((value) => String(value ?? "").toLowerCase() === "operational") ? "OPERATIONAL" : "DEGRADED";
  return {
    id: summary.id ?? detail.id ?? null,
    name: summary.name ?? detail.name ?? null,
    groupName: summary.group_name ?? detail.group_name ?? null,
    provider: summary.provider ?? detail.provider ?? null,
    status,
    primary: {
      model: summary.primary_model ?? null,
      status: upperStatus(summary.primary_status),
      latencyMs: summary.primary_latency_ms ?? null,
      pingLatencyMs: summary.primary_ping_latency_ms ?? null,
      availability: availabilityFor(models.find((item) => item.model === summary.primary_model) ?? {}, window) ?? summary.availability_7d ?? null,
      availabilityWindow: window,
    },
    models,
    recentRecordCount: timeline.length,
    collectedAt: timeline.length === 0 ? null : timeline[timeline.length - 1]?.checkedAt ?? null,
    refreshRemainingSeconds: null,
    refreshSourceStatus: "unsupported-by-native-response",
    timeline: {
      order: "PAST_TO_NOW",
      recordCount: timeline.length,
      firstAt: timeline[0]?.checkedAt ?? null,
      lastAt: timeline[timeline.length - 1]?.checkedAt ?? null,
      records: [],
      detail: "use --channel <id-or-name> for native history pagination",
    },
  };
}

function monitorTimeoutPolicy(runtimeVersion: Record<string, unknown>): Record<string, unknown> {
  const runtimeTag = typeof runtimeVersion.version === "string" && runtimeVersion.version.length > 0 ? runtimeVersion.version : null;
  const runtimeVersionMismatch = runtimeTag?.replace(/^v/u, "") !== upstreamVersion.replace(/^v/u, "");
  return {
    runtime: { image: runtimeVersion.image ?? null, version: runtimeTag },
    sourceReferenceVersion: upstreamVersion,
    runtimeVersionMismatch,
    runtimePolicyStatus: runtimeVersionMismatch ? "unverified" : "source-version-verified",
    sourceReference: {
      responseHeaderTimeoutMs: monitorResponseHeaderTimeoutMs,
      totalRequestTimeoutMs: monitorTotalRequestTimeoutMs,
      sourceStatus: "official-source-constant-verified-for-reference-version",
    },
    perUpstreamTimeout: { status: "unsupported", reason: "native monitor API does not expose this field" },
    overallGatewayDeadline: { status: "unsupported", reason: "native monitor API does not expose this field" },
    failoverReserve: { status: "unsupported", reason: "native monitor API does not expose this field" },
  };
}

function availabilityFor(model: Record<string, unknown>, window: "7d" | "15d" | "30d"): unknown {
  return model[`availability_${window}`] ?? model.availability ?? null;
}

function sourceSummary(action: "diagnosis" | "channels", status: string, runtimeVersion: Record<string, unknown> = {}): Record<string, unknown> {
  if (action === "diagnosis") {
    return {
      status,
      sourceReferenceVersion: upstreamVersion,
      runtimeVersion,
      metricsEndpoint: "/api/v1/admin/ops/dashboard/overview",
      nativeDiagnosisEndpoint: { status: "unsupported", reason: "v0.1.155 has no diagnosis/advice response schema" },
      projectionKind: "native-frontend-projection",
      ruleSource: diagnosisRuleSource,
      textSource: diagnosisTextSource,
      evidenceBoundary: "metrics are native API facts; severity, impact and advice reproduce the official v0.1.155 frontend projection and are not server-returned root-cause proof",
    };
  }
  return {
    status,
    sourceReferenceVersion: upstreamVersion,
    runtimeVersion,
    listEndpoint: "/api/v1/channel-monitors",
    detailEndpoint: "/api/v1/channel-monitors/:id/status",
    historyEndpoint: "/api/v1/admin/channel-monitors/:id/history",
    correlationSource: "heuristic projection by native record checked_at, latency_ms and model; request/failover facts come from request rows and bounded runtime logs when available",
    windows: ["7d", "15d", "30d"],
    overallStatusKind: "native-frontend-projection",
    refreshRemaining: { status: "unsupported", reason: "native response does not include a refresh countdown" },
  };
}

function querySummary(options: Sub2ApiOpsOptions): Record<string, unknown> {
  return {
    target: options.targetId,
    platform: options.platform,
    group: options.group,
    diagnosisId: options.diagnosisId,
    timeRange: options.action === "diagnosis" ? options.timeRange : undefined,
    channel: options.channel,
    model: options.model,
    window: options.action === "channels" ? options.window : undefined,
    pageToken: options.pageToken,
    recordId: options.recordId,
    snapshot: true,
    foregroundRefresh: false,
  };
}

function upperStatus(value: unknown): string {
  const text = String(value ?? "unknown").trim();
  return text.length === 0 ? "UNKNOWN" : text.toUpperCase();
}

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): string {
  return typeof value === "string" && value.length > 0 ? value : fallback;
}

function finiteNumber(value: unknown): number | null {
  return typeof value === "number" && Number.isFinite(value) ? value : null;
}

function numberAt(value: unknown, fallback: number): number {
  return finiteNumber(value) ?? fallback;
}
