/**
 * 可视化：Albany NY → SF 登录态查价连跑 10 次（复现卡住）
 *   DIAG_HEADED=true npx tsx scripts/diag-mothership-albany-sf-x10.ts
 */
import fs from "node:fs";
import path from "node:path";
import { loadDevEnv } from "@/lib/dev-env";

loadDevEnv();

const wantHeaded = process.env.DIAG_HEADED !== "false";
process.env.RPA_HEADED = wantHeaded ? "true" : "false";
process.env.RPA_HEADLESS = wantHeaded ? "false" : "true";
if (wantHeaded && !process.env.RPA_SLOW_MO_MS?.trim()) {
  process.env.RPA_SLOW_MO_MS = "120";
}
if (!wantHeaded) delete process.env.RPA_SLOW_MO_MS;

import { resolveAxelMothershipSuggest } from "@/lib/axel/candidates";
import { runWithMothershipLoginContext } from "@/lib/rpa/mothership-login-context";
import { getCustomerProviderLogin } from "@/modules/customer/provider-credentials";
import type { QuoteRequest } from "@/modules/providers/quote-provider";
import {
  buildLoggedInAddressSearchQuery,
  runMothershipLoggedInDashboardQuote,
} from "@/workers/rpa/mothership-logged-in-quote";

const RUNS = Math.max(1, Number(process.env.DIAG_RUNS || "10") || 10);
const PICKUP_Q = "101 South Pine Avenue, Albany, NY 12208, USA";
const DELIVERY_Q = "555 Market St ste 1001, San Francisco, CA, USA";
const READY_DATE = process.env.DIAG_READY_DATE?.trim() || "2026-07-20";
const READY_TIME = process.env.DIAG_READY_TIME?.trim() || "12:00 PM";

type RunRow = {
  n: number;
  ok: boolean;
  ms: number;
  lastStep: string;
  carriers: string;
  error?: string;
  failShot?: string;
};

const timingBuf: string[] = [];
const origLog = console.log.bind(console);
console.log = (...args: unknown[]) => {
  const line = args.map(String).join(" ");
  if (
    line.includes("[rpa] logged-in timing:") ||
    line.includes("[rpa] logged-in step:") ||
    line.includes("[rpa] logged-in: still no rate-card") ||
    line.includes("[rpa] logged-in: patched") ||
    line.includes("[rpa] logged-in: rate-card ready") ||
    line.includes("[rpa] logged-in FAILED")
  ) {
    timingBuf.push(line);
  }
  origLog(...args);
};

async function pickFirst(query: string) {
  const list = await resolveAxelMothershipSuggest(query);
  const hit = list.find((c) => c.selectable !== false && c.option_id.trim());
  if (!hit) throw new Error(`无联想: ${query.slice(0, 50)}`);
  return hit;
}

function toAddr(c: Awaited<ReturnType<typeof pickFirst>>) {
  return {
    street: c.street,
    city: c.city,
    state: c.state,
    zip: c.zip || "",
    placeId: c.option_id,
    formattedAddress: c.formatted_address || c.display_label,
    selectedFromSuggestions: true,
    mothershipOptionId: c.option_id,
    mothershipDisplayLabel: c.display_label,
    selectedFromMothership: true,
  };
}

function lastStepFromBuf(): string {
  for (let i = timingBuf.length - 1; i >= 0; i -= 1) {
    const m = timingBuf[i]!.match(/step="([^"]+)"/);
    if (m) return m[1]!;
    if (timingBuf[i]!.includes("still no rate-card")) return "wait rate-card (stuck)";
    if (timingBuf[i]!.includes("FAILED")) return "FAILED";
  }
  return "(none)";
}

async function main(): Promise<void> {
  const customerId = process.env.DIAG_CUSTOMER_ID?.trim() || "CUST_001";
  const login = await getCustomerProviderLogin(customerId, "mothership");
  if (!login) {
    console.error(`[diag] 无 MotherShip 账密 customer=${customerId}`);
    process.exit(1);
  }

  console.log("=== Albany→SF 可视化 ×" + RUNS + " ===");
  console.log(
    `headed=${wantHeaded} slowMo=${process.env.RPA_SLOW_MO_MS ?? 0} ready=${READY_DATE} ${READY_TIME}`,
  );

  const [pickupC, deliveryC] = await Promise.all([
    pickFirst(PICKUP_Q),
    pickFirst(DELIVERY_Q),
  ]);
  console.log(
    `[diag] pickup=${buildLoggedInAddressSearchQuery(toAddr(pickupC))}`,
  );
  console.log(
    `[diag] delivery=${buildLoggedInAddressSearchQuery(toAddr(deliveryC))}`,
  );

  const rows: RunRow[] = [];
  for (let n = 1; n <= RUNS; n += 1) {
    timingBuf.length = 0;
    const t0 = Date.now();
    console.log(`\n---------- RUN ${n}/${RUNS} ----------`);
    const req: QuoteRequest = {
      cargoHash: `diag-albany-sf-${n}-${Date.now()}`,
      pickup: toAddr(pickupC),
      delivery: toAddr(deliveryC),
      weightLb: 120,
      dimsIn: { l: 48, w: 40, h: 48 },
      palletCount: 2,
      cargoType: "box",
      readyDate: READY_DATE,
      readyTime: READY_TIME,
      pickupAccessorials: ["residential", "liftgate"],
      deliveryAccessorials: ["cfs", "fbaAppointment"],
      cargoLines: [
        {
          cargoType: "box",
          quantity: 2,
          weightLb: 120,
          lengthIn: 48,
          widthIn: 40,
          heightIn: 48,
        },
      ],
    };

    try {
      const items = await runWithMothershipLoginContext(login, "customer", () =>
        runMothershipLoggedInDashboardQuote(req),
      );
      const ms = Date.now() - t0;
      const carriers = items.map((i) => `${i.carrier}=$${i.rawTotal}`).join(", ");
      rows.push({
        n,
        ok: true,
        ms,
        lastStep: lastStepFromBuf(),
        carriers,
      });
      console.log(`[diag] RUN ${n} OK ${ms}ms ${carriers}`);
    } catch (err) {
      const ms = Date.now() - t0;
      const msg = err instanceof Error ? err.message : String(err);
      const diagDir = path.join(process.cwd(), ".rpa", "diag");
      const shots = fs.existsSync(diagDir)
        ? fs
            .readdirSync(diagDir)
            .filter((f) => f.startsWith("logged-in-fail-") && f.endsWith(".png"))
            .sort()
        : [];
      rows.push({
        n,
        ok: false,
        ms,
        lastStep: lastStepFromBuf(),
        carriers: "",
        error: msg.slice(0, 200),
        failShot: shots.at(-1),
      });
      console.log(`[diag] RUN ${n} FAIL ${ms}ms step=${lastStepFromBuf()} err=${msg.slice(0, 160)}`);
    }
  }

  const okN = rows.filter((r) => r.ok).length;
  const reportPath = path.join(
    process.cwd(),
    ".rpa",
    "diag",
    `albany-sf-x10-${new Date().toISOString().replace(/[:.]/g, "-")}.md`,
  );
  const md = [
    `# Albany→SF ×${RUNS} headed`,
    "",
    `- ok=${okN}/${RUNS}`,
    `- pickup=${PICKUP_Q}`,
    `- delivery=${DELIVERY_Q}`,
    "",
    "| # | ok | ms | lastStep | carriers/error |",
    "|---|----|----|----------|----------------|",
    ...rows.map((r) => {
      const detail = r.ok
        ? r.carriers
        : `${r.error ?? ""}${r.failShot ? ` shot=${r.failShot}` : ""}`;
      return `| ${r.n} | ${r.ok ? "Y" : "N"} | ${r.ms} | ${r.lastStep} | ${detail.replace(/\|/g, "/")} |`;
    }),
    "",
  ].join("\n");
  fs.mkdirSync(path.dirname(reportPath), { recursive: true });
  fs.writeFileSync(reportPath, md, "utf8");
  console.log("\n=== SUMMARY ===");
  console.log(`ok=${okN}/${RUNS} report=${reportPath}`);
  for (const r of rows) {
    console.log(
      `  #${r.n} ${r.ok ? "OK" : "FAIL"} ${r.ms}ms last=${r.lastStep}${r.error ? " " + r.error.slice(0, 80) : ""}`,
    );
  }
  process.exit(okN === RUNS ? 0 : 1);
}

main().catch((e) => {
  console.error(e);
  process.exit(1);
});
