/**
 * 5 组登录态 MotherShip 查价计时
 *   DIAG_HEADED=false npx tsx scripts/diag-mothership-timing-5cases.ts
 */
import fs from "node:fs";
import path from "node:path";
import { loadDevEnv } from "@/lib/dev-env";

loadDevEnv();

const wantHeaded = process.env.DIAG_HEADED === "true";
process.env.RPA_HEADED = wantHeaded ? "true" : "false";
process.env.RPA_HEADLESS = wantHeaded ? "false" : "true";
if (!wantHeaded) delete process.env.RPA_SLOW_MO_MS;
else if (!process.env.RPA_SLOW_MO_MS?.trim()) process.env.RPA_SLOW_MO_MS = "0";

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 READY_DATE = process.env.DIAG_READY_DATE?.trim() || "2026-07-20";
const READY_TIME = process.env.DIAG_READY_TIME?.trim() || "12:00 PM";

const LANES = [
  {
    id: 1,
    name: "Brea→Fairhope",
    pickup: "789 East Elm Street suite 301, Brea, CA, USA",
    delivery: "456 Oak Avenue unit 207, Fairhope, AL, USA",
  },
  {
    id: 2,
    name: "LA→SF",
    pickup:
      "2020 West Washington Boulevard floor 5 rm 508, Los Angeles, CA, USA",
    delivery: "555 Market St ste 1001, San Francisco, CA, USA",
  },
  {
    id: 3,
    name: "MA→OR",
    pickup: "789 Elm Street, East Bridgewater, MA, USA",
    delivery: "888 Liberty Street Northeast, Salem, OR, USA",
  },
  {
    id: 4,
    name: "Dallas→Chicago",
    pickup: "1234 Main Street, Dallas, TX, USA",
    delivery: "200 East Randolph Street, Chicago, IL, USA",
  },
  {
    id: 5,
    name: "Atlanta→Denver",
    pickup: "100 Peachtree Street NW, Atlanta, GA, USA",
    delivery: "1701 California Street, Denver, CO, USA",
  },
] as const;

type StepTiming = { step: string; ms: number; totalMs: number };
type CaseResult = {
  id: number;
  name: string;
  ok: boolean;
  suggestMs: number;
  rpaMs: number;
  wallMs: number;
  carrierCount: number;
  carriers: string;
  error?: string;
  steps: StepTiming[];
  addressPickMs: { pickup?: number; delivery?: number };
};

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: address picked")
  ) {
    timingBuf.push(line);
  }
  origLog(...args);
};

async function pickFirst(query: string) {
  const t0 = Date.now();
  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, ms: Date.now() - t0 };
}

function toAddr(c: Awaited<ReturnType<typeof pickFirst>>["hit"]) {
  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 parseTimings(lines: string[]): {
  steps: StepTiming[];
  addressPickMs: { pickup?: number; delivery?: number };
  totalMs?: number;
} {
  const steps: StepTiming[] = [];
  const addressPickMs: { pickup?: number; delivery?: number } = {};
  let totalMs: number | undefined;

  for (const line of lines) {
    const stepM = line.match(
      /timing: step="([^"]+)" ms=(\d+) totalMs=(\d+)/,
    );
    if (stepM) {
      steps.push({
        step: stepM[1]!,
        ms: Number(stepM[2]),
        totalMs: Number(stepM[3]),
      });
      continue;
    }
    const doneM = line.match(/timing: DONE label=\w+ totalMs=(\d+)/);
    if (doneM) {
      totalMs = Number(doneM[1]);
      continue;
    }
    const pickM = line.match(
      /address picked side=(pickup|delivery) via=\w+ ms=(\d+)/,
    );
    if (pickM) {
      addressPickMs[pickM[1] as "pickup" | "delivery"] = Number(pickM[2]);
    }
  }

  return { steps, addressPickMs, totalMs };
}

async function runCase(
  login: { email: string; password: string },
  lane: (typeof LANES)[number],
): Promise<CaseResult> {
  timingBuf.length = 0;
  const wall0 = Date.now();

  const suggest0 = Date.now();
  const [p, d] = await Promise.all([
    pickFirst(lane.pickup),
    pickFirst(lane.delivery),
  ]);
  const suggestMs = Date.now() - suggest0;

  const req: QuoteRequest = {
    cargoHash: `timing5-${lane.id}-${Date.now()}`,
    pickup: toAddr(p.hit),
    delivery: toAddr(d.hit),
    weightLb: 250,
    dimsIn: { l: 60, w: 50, h: 60 },
    palletCount: 2,
    cargoType: "general_freight",
    readyDate: READY_DATE,
    readyTime: READY_TIME,
    cargoLines: [
      {
        cargoType: "general_freight",
        quantity: 2,
        weightLb: 250,
        lengthIn: 60,
        widthIn: 50,
        heightIn: 60,
      },
    ],
  };

  console.log(
    `\n=== #${lane.id} ${lane.name} ===\npickup=${buildLoggedInAddressSearchQuery(req.pickup)}\ndelivery=${buildLoggedInAddressSearchQuery(req.delivery)}`,
  );

  const rpa0 = Date.now();
  try {
    const items = await runWithMothershipLoginContext(login, "customer", () =>
      runMothershipLoggedInDashboardQuote(req),
    );
    const rpaMs = Date.now() - rpa0;
    const wallMs = Date.now() - wall0;
    const parsed = parseTimings([...timingBuf]);
    return {
      id: lane.id,
      name: lane.name,
      ok: true,
      suggestMs,
      rpaMs,
      wallMs,
      carrierCount: items.length,
      carriers: items.map((i) => i.carrier).join(", "),
      steps: parsed.steps,
      addressPickMs: parsed.addressPickMs,
    };
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    const parsed = parseTimings([...timingBuf]);
    return {
      id: lane.id,
      name: lane.name,
      ok: false,
      suggestMs,
      rpaMs: Date.now() - rpa0,
      wallMs: Date.now() - wall0,
      carrierCount: 0,
      carriers: "",
      error: msg.slice(0, 200),
      steps: parsed.steps,
      addressPickMs: parsed.addressPickMs,
    };
  }
}

function fmtMs(ms: number): string {
  return (ms / 1000).toFixed(1) + "s";
}

function stepMs(steps: StepTiming[], needle: string): string {
  const hit = steps.find((s) => s.step.includes(needle));
  return hit ? String(hit.ms) : "-";
}

async function main(): Promise<void> {
  const login = await getCustomerProviderLogin("CUST_001", "mothership");
  if (!login) {
    console.error("无 MotherShip 账密");
    process.exit(1);
  }

  console.log("=== MotherShip 5 组计时 ===");
  console.log(`headed=${wantHeaded} ready=${READY_DATE} ${READY_TIME}`);
  console.log("cargo=Pallet qty=2 wt=250 dims=60x50x60\n");

  const batch0 = Date.now();
  const results: CaseResult[] = [];
  for (const lane of LANES) {
    results.push(await runCase(login, lane));
  }
  const batchMs = Date.now() - batch0;

  const lines: string[] = [
    "# MotherShip 登录态 5 组计时",
    "",
    `批次总耗时: **${fmtMs(batchMs)}** (${batchMs}ms)`,
    `提货日: ${READY_DATE} ${READY_TIME}`,
    "",
    "## 汇总",
    "",
    "| # | 车道 | 结果 | 联想 | RPA | 全程 | 承运商数 | 提货址 | 派送址 |",
    "|---|------|------|------|-----|------|----------|--------|--------|",
  ];

  for (const r of results) {
    lines.push(
      `| ${r.id} | ${r.name} | ${r.ok ? "OK" : "FAIL"} | ${fmtMs(r.suggestMs)} | ${fmtMs(r.rpaMs)} | ${fmtMs(r.wallMs)} | ${r.carrierCount} | ${r.addressPickMs.pickup ?? "-"}ms | ${r.addressPickMs.delivery ?? "-"}ms |`,
    );
  }

  lines.push("", "## 逐步耗时 (ms)", "");
  for (const r of results) {
    lines.push(`### #${r.id} ${r.name} ${r.ok ? "OK" : "FAIL"}`);
    if (r.error) lines.push(`- 错误: ${r.error}`);
    lines.push(
      `- 联想 ${r.suggestMs}ms | RPA ${r.rpaMs}ms | 全程 ${r.wallMs}ms`,
    );
    if (r.carriers) lines.push(`- 承运商: ${r.carriers}`);
    lines.push("");
    lines.push("| 步骤 | 本步 ms | 累计 ms |");
    lines.push("|------|---------|---------|");
    for (const s of r.steps) {
      lines.push(`| ${s.step} | ${s.ms} | ${s.totalMs} |`);
    }
    lines.push("");
  }

  const report = lines.join("\n");
  const outDir = path.join(process.cwd(), ".rpa", "diag");
  fs.mkdirSync(outDir, { recursive: true });
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
  const mdPath = path.join(outDir, `timing-5cases-${stamp}.md`);
  const jsonPath = path.join(outDir, `timing-5cases-${stamp}.json`);
  fs.writeFileSync(mdPath, report, "utf8");
  fs.writeFileSync(
    jsonPath,
    JSON.stringify({ batchMs, results }, null, 2),
    "utf8",
  );

  console.log("\n" + report);
  console.log(`\n报告: ${mdPath}`);

  const fails = results.filter((r) => !r.ok);
  if (fails.length) {
    console.error(`失败 ${fails.length}/5: ${fails.map((f) => f.name).join(", ")}`);
    process.exit(1);
  }
}

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