import { CLOUD_API_SERVICE_ID } from "../audit/index.mjs";
import { describeCodeAgentAvailability } from "./code-agent-chat.ts";
import {
  applyRuntimeDbReadinessLayers,
  buildDbRuntimeReadiness
} from "./db-contract.ts";
import { buildCloudApiReadiness } from "./health-contract.ts";
import {
  M3_IO_CONTROL_ROUTE,
  describeM3IoControlLive
} from "./m3-io-control.ts";

const STATUS = Object.freeze({
  pass: "通过",
  blocked: "阻塞",
  failed: "失败",
  pending: "待验证",
  info: "信息"
});

export async function buildGateDiagnosticsRows(options = {}) {
  const observedAt = new Date().toISOString();
  const rows = [];
  const health = await observeHealth(options, observedAt);
  const m3 = await observeM3(options, observedAt);
  const audit = await observeAudit(options, observedAt);
  const evidence = await observeEvidence(options, observedAt);

  rows.push(...health.rows, m3.row, audit.row, evidence.row);

  const status = rows.some((row) => row.statusKey === "failed")
    ? "failed"
    : rows.some((row) => row.statusKey === "blocked")
      ? "blocked"
      : rows.some((row) => row.statusKey === "pending")
        ? "pending"
      : "pass";

  return {
    serviceId: CLOUD_API_SERVICE_ID,
    route: "/v1/diagnostics/gate",
    contractVersion: "gate-diagnostics-table-v1",
    status,
    sourceKind: "LIVE-BACKEND",
    liveBackend: true,
    observedAt,
    rowCount: rows.length,
    columns: ["类别", "检查项", "状态", "归因对象", "关键细节", "证据/trace", "更新时间", "下一步"],
    rows,
    safety: {
      frontendHardcodedRows: false,
      sourceFixturePromoted: false,
      localStorageUsed: false,
      blockedIsGreen: false,
      hardwareControlSurface: false,
      codeAgentConversationSurface: false
    }
  };
}

async function observeHealth(options, observedAt) {
  try {
    const env = options.env ?? process.env;
    const dbProbe = await buildDbRuntimeReadiness(env, options.dbProbe);
    const runtime = await runtimeReadiness(options.runtimeStore);
    const db = applyRuntimeDbReadinessLayers(dbProbe, runtime);
    const codeAgent = await describeCodeAgentAvailability(env, options);
    const readiness = buildCloudApiReadiness({ db, codeAgent, runtime });
    const commitId = env.HWLAB_COMMIT_ID || env.HWLAB_GIT_SHA || "unknown";
    const imageTag = env.HWLAB_IMAGE_TAG || shortHash(commitId);
    return {
      rows: [
        row({
          category: "部署",
          check: "Cloud API 实况身份",
          statusKey: commitId === "unknown" ? "info" : "pass",
          owner: CLOUD_API_SERVICE_ID,
          detail: `service=${CLOUD_API_SERVICE_ID}; env=dev; status=${readiness.status}; imageTag=${imageTag}`,
          evidence: [`commit=${commitId}`, "GET /health/live"],
          updatedAt: observedAt,
          next: readiness.ready ? "继续保持与 DEV desired state 对齐。" : "先处理下方阻塞行，再重新执行 DEV live 复核。"
        }),
        row({
          category: "健康检查",
          check: "/health/live readiness",
          statusKey: readiness.ready ? "pass" : "blocked",
          owner: CLOUD_API_SERVICE_ID,
          detail: `ready=${readiness.ready}; status=${readiness.status}; blockers=${readiness.blockerCodes.join(",") || "无"}`,
          evidence: readiness.blockerCodes.length > 0 ? readiness.blockerCodes.map((code) => `blocker=${code}`) : ["GET /health/live"],
          updatedAt: observedAt,
          next: readiness.ready ? "无额外动作。" : "按 blocker code 分别处理 DB、runtime、Code Agent 或 M3 依赖。"
        }),
        row({
          category: "DB",
          check: "DB live readiness",
          statusKey: db?.ready && db?.connected && db?.liveDbEvidence ? "pass" : "blocked",
          owner: "hwlab-cloud-api / DEV Postgres",
          detail: `ready=${Boolean(db?.ready)}; connected=${Boolean(db?.connected)}; liveDbEvidence=${Boolean(db?.liveDbEvidence)}; endpointSource=${db?.endpointSource ?? "unknown"}`,
          evidence: db?.blocker ? [`blocker=${db.blocker}`] : ["db.liveDbEvidence=true"],
          updatedAt: observedAt,
          next: db?.ready && db?.connected && db?.liveDbEvidence
            ? "继续保持 Secret URL host 与 live DB 证据分层。"
            : "修复 DEV DB env/连接/auth，且不打印 Secret 值。"
        }),
        row({
          category: "运行态",
          check: "runtime durable adapter",
          statusKey: runtime?.durable === true && runtime?.ready === true && runtime?.liveRuntimeEvidence === true ? "pass" : "blocked",
          owner: "hwlab-cloud-api runtime-store",
          detail: `adapter=${runtime?.adapter ?? "unknown"}; durable=${Boolean(runtime?.durable)}; ready=${Boolean(runtime?.ready)}; liveRuntimeEvidence=${Boolean(runtime?.liveRuntimeEvidence)}`,
          evidence: [
            runtime?.blocker ? `blocker=${runtime.blocker}` : null,
            runtime?.durabilityContract?.blockedLayer ? `blockedLayer=${runtime.durabilityContract.blockedLayer}` : null,
            runtime?.connection?.queryResult ? `queryResult=${runtime.connection.queryResult}` : null
          ].filter(Boolean),
          updatedAt: observedAt,
          next: runtime?.durable === true && runtime?.ready === true && runtime?.liveRuntimeEvidence === true
            ? "可作为可信记录持久化前置。"
            : "修复 runtime durable auth/schema/migration/readiness 后再升级可信闭环。"
        }),
        row({
          category: "Code Agent",
          check: "provider readiness",
          statusKey: codeAgent?.ready && codeAgent?.status !== "blocked" ? "pass" : "blocked",
          owner: "hwlab-cloud-api / Code Agent provider",
          detail: `status=${codeAgent?.status ?? "unknown"}; provider=${codeAgent?.provider ?? "unknown"}; model=${codeAgent?.model ?? "unknown"}; backend=${codeAgent?.backend ?? "unknown"}`,
          evidence: [
            codeAgent?.reason ? `reason=${codeAgent.reason}` : null,
            ...(Array.isArray(codeAgent?.missingEnv) ? codeAgent.missingEnv.map((name) => `missingEnv=${name}`) : []),
            "Secret 值未读取/未展示"
          ].filter(Boolean),
          updatedAt: observedAt,
          next: codeAgent?.ready && codeAgent?.status !== "blocked"
            ? "继续用受控 /v1/agent/chat 验证真实 runner 能力。"
            : "补齐 provider env/Secret/egress 后复测，不用 mock 回复冒充。"
        })
      ]
    };
  } catch (error) {
    return {
      rows: [
        row({
          category: "健康检查",
          check: "后端聚合读取",
          statusKey: "failed",
          owner: CLOUD_API_SERVICE_ID,
          detail: `live 聚合失败：${oneLine(error.message)}`,
          evidence: "GET /v1/diagnostics/gate",
          updatedAt: observedAt,
          next: "先修复 cloud-api 聚合接口，再重新刷新内部复核表。"
        })
      ]
    };
  }
}

async function observeM3(options, observedAt) {
  try {
    const payload = await describeM3IoControlLive(options);
    const ready = payload?.readiness?.status === "ready" && payload?.readiness?.controlReady === true;
    return {
      row: row({
        category: "M3",
        check: "DO1 经 hwlab-patch-panel 同步到 DI1",
        statusKey: ready ? "pass" : payload?.readiness?.status === "pending" ? "pending" : "blocked",
        owner: "hwlab-cloud-api / hwlab-patch-panel",
        detail: payload?.readiness?.summary ?? payload?.blockedReason ?? "M3 IO readiness 未返回摘要。",
        evidence: [
          `route=${M3_IO_CONTROL_ROUTE}`,
          payload?.readiness?.sourceKind ? `sourceKind=${payload.readiness.sourceKind}` : null,
          payload?.readiness?.blocker?.code ? `blocker=${payload.readiness.blocker.code}` : null,
          payload?.readiness?.blocker?.layer ? `layer=${payload.readiness.blocker.layer}` : null
        ].filter(Boolean),
        updatedAt: payload?.readiness?.observedAt ?? observedAt,
        next: ready
          ? "只表示控制路径可执行；M3 验收仍需 operation/trace/audit/evidence 闭环。"
          : payload?.readiness?.blocker?.zh ?? "修复 gateway-simu、box-simu 或 patch-panel 只读 readiness 后再复核。"
      })
    };
  } catch (error) {
    return {
      row: row({
        category: "M3",
        check: "DO1 经 hwlab-patch-panel 同步到 DI1",
        statusKey: "failed",
        owner: "hwlab-cloud-api / hwlab-patch-panel",
        detail: `M3 live readiness 读取失败：${oneLine(error.message)}`,
        evidence: `GET ${M3_IO_CONTROL_ROUTE}`,
        updatedAt: observedAt,
        next: "先恢复 M3 IO readiness 接口，再验证 patch-panel 目标链路。"
      })
    };
  }
}

async function observeAudit(options, observedAt) {
  try {
    const result = await options.runtimeStore?.queryAuditEvents?.({ limit: 6 });
    const events = Array.isArray(result?.events) ? result.events : [];
    return {
      row: row({
        category: "证据",
        check: "audit.event.query",
        statusKey: events.length > 0 ? "info" : "pending",
        owner: "runtime-store / audit",
        detail: `只读查询返回 ${events.length} 条 audit；该行不单独证明 M3 通过。`,
        evidence: events.slice(0, 3).map((event) => [
          event.auditId ? `audit=${event.auditId}` : null,
          event.traceId ? `trace=${event.traceId}` : null
        ].filter(Boolean).join(" / ")).filter(Boolean),
        updatedAt: observedAt,
        next: events.length > 0 ? "将 audit 与 operation/evidence 绑定后再判断可信闭环。" : "等待 live audit 记录，或先修复 runtime durable blocker。"
      })
    };
  } catch (error) {
    return {
      row: row({
        category: "证据",
        check: "audit.event.query",
        statusKey: "blocked",
        owner: "runtime-store / audit",
        detail: `只读 audit 查询受阻：${oneLine(error.message)}`,
        evidence: "POST /json-rpc audit.event.query",
        updatedAt: observedAt,
        next: "修复 runtime durable/readiness 后再查询 audit，不用 SOURCE 回退冒充。"
      })
    };
  }
}

async function observeEvidence(options, observedAt) {
  try {
    const result = await options.runtimeStore?.queryEvidenceRecords?.({ limit: 6 });
    const records = Array.isArray(result?.records) ? result.records : [];
    return {
      row: row({
        category: "证据",
        check: "evidence.record.query",
        statusKey: records.length > 0 ? "info" : "pending",
        owner: "runtime-store / evidence",
        detail: `只读查询返回 ${records.length} 条 evidence；该行不单独证明 M3 通过。`,
        evidence: records.slice(0, 3).map((record) => [
          record.evidenceId ? `evidence=${record.evidenceId}` : null,
          record.traceId ?? record.metadata?.traceId ? `trace=${record.traceId ?? record.metadata?.traceId}` : null
        ].filter(Boolean).join(" / ")).filter(Boolean),
        updatedAt: observedAt,
        next: records.length > 0 ? "将 evidence 与 operation/audit/patch-panel live report 绑定后再判断。" : "等待 live evidence 记录，或先修复 runtime durable blocker。"
      })
    };
  } catch (error) {
    return {
      row: row({
        category: "证据",
        check: "evidence.record.query",
        statusKey: "blocked",
        owner: "runtime-store / evidence",
        detail: `只读 evidence 查询受阻：${oneLine(error.message)}`,
        evidence: "POST /json-rpc evidence.record.query",
        updatedAt: observedAt,
        next: "修复 runtime durable/readiness 后再查询 evidence，不用 SOURCE 回退冒充。"
      })
    };
  }
}

async function runtimeReadiness(runtimeStore) {
  if (typeof runtimeStore?.readiness === "function") {
    return runtimeStore.readiness();
  }
  if (typeof runtimeStore?.summary === "function") {
    return runtimeStore.summary();
  }
  return {
    adapter: "unknown",
    durable: false,
    ready: false,
    liveRuntimeEvidence: false,
    blocker: "runtime_store_unavailable"
  };
}

function row({ category, check, statusKey, owner, detail, evidence, updatedAt, next }) {
  const normalizedStatusKey = normalizeStatusKey(statusKey);
  return {
    category,
    check,
    status: STATUS[normalizedStatusKey],
    statusKey: normalizedStatusKey,
    owner,
    detail: oneLine(detail),
    evidence: normalizeEvidence(evidence),
    updatedAt,
    next: oneLine(next),
    sourceKind: "LIVE-BACKEND"
  };
}

function normalizeStatusKey(statusKey) {
  const normalized = String(statusKey ?? "").trim().toLowerCase();
  if (normalized === "pass" || normalized === "passed" || normalized === "ok" || normalized === "ready") return "pass";
  if (normalized === "failed" || normalized === "failure" || normalized === "error") return "failed";
  if (normalized === "pending" || normalized === "unknown" || normalized === "loading") return "pending";
  if (normalized === "info" || normalized === "information") return "info";
  return "blocked";
}

function normalizeEvidence(value) {
  const items = Array.isArray(value) ? value : [value];
  const normalized = items.map(oneLine).filter(Boolean);
  return normalized.length > 0 ? normalized : ["live 后端未返回可用 evidence 字段"];
}

function oneLine(value) {
  return String(value ?? "").replace(/\s+/gu, " ").trim().slice(0, 360);
}

function shortHash(value) {
  const text = String(value ?? "unknown");
  return text === "unknown" ? "unknown" : text.slice(0, 7);
}
