#!/usr/bin/env tsx
/**
 * 阶段0 录证产物机器验收
 * 用法: npm run verify:phase0
 */
import fs from "node:fs";
import { countAxelQuoteTiers } from "./lib/axel-quote-contract";
import {
  listHarEntries,
  pickBestQuoteEntry,
  readHarFile,
  scoreQuoteBody,
} from "./lib/har-parse";
import {
  BASELINE_HAR,
  QUOTE_CONTRACT_SCHEMA,
  SESSION_STORAGE_SNAPSHOT,
} from "./lib/paths";

const QUOTE_CONTRACT_SUMMARY = `${process.cwd()}/.rpa/phase0/quote-contract-summary.json`;

type AssertionResult = {
  id: string;
  description: string;
  pass: boolean;
  detail: string;
};

function collectPlaceIds(node: unknown, out: string[]): void {
  if (node == null) {
    return;
  }
  if (Array.isArray(node)) {
    for (const item of node) {
      collectPlaceIds(item, out);
    }
    return;
  }
  if (typeof node !== "object") {
    return;
  }
  for (const [key, value] of Object.entries(node as Record<string, unknown>)) {
    if (/place[_-]?id/i.test(key) && typeof value === "string" && value.trim()) {
      out.push(value.trim());
    }
    collectPlaceIds(value, out);
  }
}

function countRateLeaves(node: unknown): {
  pricedLeafCount: number;
  fourTierOk: boolean;
  availableRateCount: number;
} {
  return countAxelQuoteTiers(node);
}

function runAssertions(): AssertionResult[] {
  const results: AssertionResult[] = [];

  // A1: baseline.har 存在且含网络条目
  const harExists = fs.existsSync(BASELINE_HAR);
  let harEntryCount = 0;
  if (harExists) {
    harEntryCount = listHarEntries(readHarFile(BASELINE_HAR)).length;
  }
  results.push({
    id: "A1",
    description: "baseline.har 存在且 entries.length ≥ 10",
    pass: harExists && harEntryCount >= 10,
    detail: harExists
      ? `entries=${harEntryCount}`
      : `文件不存在: ${BASELINE_HAR}`,
  });

  // A2: HAR 中含可识别的 quote JSON 响应
  let quotePicked: ReturnType<typeof pickBestQuoteEntry> = null;
  if (harExists) {
    quotePicked = pickBestQuoteEntry(listHarEntries(readHarFile(BASELINE_HAR)));
  }
  results.push({
    id: "A2",
    description: "HAR 中存在 score>0 的 quote JSON 响应",
    pass: quotePicked != null,
    detail: quotePicked
      ? `${quotePicked.entry.request.method} ${quotePicked.entry.request.url}`
      : "未匹配 axel/quote 或 rates 结构",
  });

  // A3: axel/quote 四档齐全（data.rates）或 availableRates ≥ 4
  const tierStats = quotePicked
    ? countRateLeaves(quotePicked.body)
    : { pricedLeafCount: 0, fourTierOk: false, availableRateCount: 0 };
  const a3Pass = tierStats.fourTierOk || tierStats.pricedLeafCount >= 4;
  results.push({
    id: "A3",
    description:
      "data.rates 四档齐全（std/guar × lowest/fastest）或 availableRates ≥ 4",
    pass: a3Pass,
    detail: `fourTier=${tierStats.fourTierOk} data.rates leaves=${tierStats.pricedLeafCount} availableRates=${tierStats.availableRateCount}`,
  });

  if (quotePicked) {
    fs.writeFileSync(
      QUOTE_CONTRACT_SUMMARY,
      `${JSON.stringify(
        {
          verifiedAt: new Date().toISOString(),
          sourceUrl: quotePicked.entry.request.url,
          ...tierStats,
          endpoint: "POST https://services.mothership.com/axel/quote",
          mappingNotes: {
            standardLowest: "data.rates.standard.lowest",
            standardFastest: "data.rates.standard.fastest",
            guaranteedLowest: "data.rates.guaranteed.lowest",
            guaranteedFastest: "data.rates.guaranteed.fastest",
            allRates: "data.availableRates",
          },
        },
        null,
        2,
      )}\n`,
      "utf8",
    );
  }

  // A4: place_id 非空且匹配正则
  const PLACE_ID_RE = /^[A-Za-z0-9_-]{8,128}$/;
  const placeIds: string[] = [];
  if (quotePicked) {
    collectPlaceIds(quotePicked.body, placeIds);
  }
  const snapshotRaw = fs.existsSync(SESSION_STORAGE_SNAPSHOT)
    ? fs.readFileSync(SESSION_STORAGE_SNAPSHOT, "utf8")
    : "";
  if (snapshotRaw) {
    collectPlaceIds(JSON.parse(snapshotRaw) as unknown, placeIds);
  }
  const validPlaceIds = [...new Set(placeIds)].filter((id) =>
    PLACE_ID_RE.test(id),
  );
  results.push({
    id: "A4",
    description: "place_id 字段非空且匹配 ^[A-Za-z0-9_-]{8,128}$",
    pass: validPlaceIds.length >= 1,
    detail:
      validPlaceIds.length > 0
        ? `matched=${validPlaceIds.slice(0, 3).join(", ")}`
        : `found=${placeIds.length} raw, none matched regex`,
  });

  // A5: session-storage-snapshot 含 cookies + origins
  let snapshotOk = false;
  let snapshotDetail = "文件不存在";
  if (fs.existsSync(SESSION_STORAGE_SNAPSHOT)) {
    const snap = JSON.parse(
      fs.readFileSync(SESSION_STORAGE_SNAPSHOT, "utf8"),
    ) as {
      storageState?: { cookies?: unknown[]; origins?: unknown[] };
      checkpoint?: string;
    };
    const cookies = snap.storageState?.cookies?.length ?? 0;
    const origins = snap.storageState?.origins?.length ?? 0;
    const pageUrl =
      typeof (snap as { pageUrl?: string }).pageUrl === "string"
        ? (snap as { pageUrl: string }).pageUrl
        : "";
    snapshotOk =
      snap.checkpoint === "address_locked" &&
      snap.storageState != null &&
      pageUrl.includes("mothership");
    snapshotDetail = `checkpoint=${snap.checkpoint ?? "?"} cookies=${cookies} origins=${origins} url=${pageUrl || "?"}`;
  }
  results.push({
    id: "A5",
    description:
      "session-storage-snapshot.json 含 storageState（cookies + origins）且 checkpoint=address_locked",
    pass: snapshotOk,
    detail: snapshotDetail,
  });

  // A6: quote-contract.schema.json 为有效 JSON Schema 且非 incomplete 占位
  let schemaOk = false;
  let schemaDetail = "文件不存在";
  if (fs.existsSync(QUOTE_CONTRACT_SCHEMA)) {
    const schema = JSON.parse(
      fs.readFileSync(QUOTE_CONTRACT_SCHEMA, "utf8"),
    ) as {
      $schema?: string;
      body?: unknown;
      incomplete?: boolean;
      sourceHar?: { url?: string };
    };
    schemaOk =
      Boolean(schema.$schema) &&
      schema.body != null &&
      schema.incomplete !== true &&
      Boolean(schema.sourceHar?.url);
    schemaDetail = schemaOk
      ? `source=${schema.sourceHar?.url}`
      : schema.incomplete
        ? "incomplete 占位，需重新录证"
        : "缺少 $schema/body/sourceHar";
  }
  results.push({
    id: "A6",
    description:
      "quote-contract.schema.json 有效且 sourceHar 指向真实 quote endpoint",
    pass: schemaOk,
    detail: schemaDetail,
  });

  // A7: quote body score ≥ 5（含 rates+standard+guaranteed）
  const quoteScore = quotePicked ? scoreQuoteBody(quotePicked.body) : 0;
  results.push({
    id: "A7",
    description: "quote 响应结构 score ≥ 5（含 rates/standard/guaranteed 信号）",
    pass: quoteScore >= 5,
    detail: `score=${quoteScore}`,
  });

  return results;
}

function main(): void {
  const results = runAssertions();
  const failed = results.filter((r) => !r.pass);

  console.log("\n=== 阶段0 录证验收 ===\n");
  for (const r of results) {
    const mark = r.pass ? "PASS" : "FAIL";
    console.log(`[${mark}] ${r.id}: ${r.description}`);
    console.log(`       ${r.detail}\n`);
  }

  if (failed.length > 0) {
    console.error(`验收未通过: ${failed.length}/${results.length} 项失败`);
    console.error("请重新执行 npm run record:phase0 并完成完整人工流程");
    process.exit(1);
  }

  console.log(`验收通过: ${results.length}/${results.length}`);
}

main();
