/**
 * Flock Freight 登录态 ×20：多线路 / 多货物 / 多地点类型与选项
 *   DIAG_HEADED=false npx tsx scripts/diag-flock-logged-in-x20.ts
 *   DIAG_ONLY=3  — 仅跑第 3 组
 *
 * 报告：.rpa/diag/flock-logged-in-x20-*.md
 */
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;
process.env.FLOCK_WORKER_REUSE_SESSION =
  process.env.FLOCK_WORKER_REUSE_SESSION?.trim() || "false";

import { fitsFlockTrailerCargo } from "@/lib/constants/flock-limits";
import {
  defaultFlockPickupDateIso,
  flockPickupDisplayFromIso,
} from "@/lib/flock/pickup-date";
import {
  isMothershipWeekendIso,
  snapMothershipReadyDateToWeekday,
  toIsoDateLocal,
} from "@/lib/mothership/logged-in-constraints";
import { getCustomerProviderLogin } from "@/modules/customer/provider-credentials";
import { runFlockQuoteRpa } from "@/workers/rpa/flock/run-quote";
import type { FlockQuoteInput } from "@/workers/rpa/flock/types";

const PICKUP_BASE = snapMothershipReadyDateToWeekday(
  process.env.DIAG_READY_DATE?.trim() || defaultFlockPickupDateIso(),
);

const DELAY_MS = Number(process.env.DIAG_DELAY_MS ?? "2000");

type CaseDef = {
  name: string;
  pickupZip: string;
  deliveryZip: string;
  palletCount: number;
  totalWeightLb: number;
  lengthIn: number;
  widthIn: number;
  heightIn: number;
  pickupLocationType: string;
  deliveryLocationType: string;
  packagingType: string;
  freightClass?: string;
  description?: string;
  stackable?: boolean;
  turnable?: boolean;
  additionalServices?: string[];
  vehicleTypes?: string[];
  pickupLiftgate?: boolean;
  pickupInside?: boolean;
  pickupPalletJack?: boolean;
  deliveryLiftgate?: boolean;
  deliveryInside?: boolean;
  deliveryPalletJack?: boolean;
  callBeforePickup?: boolean;
  callBeforeDelivery?: boolean;
  /** 相对 PICKUP_BASE 再偏移工作日天数 */
  readyOffsetDays?: number;
};

/** 20 组：跨区 ZIP + 货物 + 地点类型 / 包装 / 附加服务差异 */
export const FLOCK_LOGGED_IN_X20_CASES: CaseDef[] = [
  {
    name: "Gardena→Pittsburgh 基线",
    pickupZip: "90248",
    deliveryZip: "15222",
    palletCount: 2,
    totalWeightLb: 500,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "bags",
    freightClass: "density",
    description: "papers",
    additionalServices: ["unloading"],
    stackable: true,
  },
  {
    name: "LA→SF + 无月台尾板",
    pickupZip: "90001",
    deliveryZip: "94102",
    palletCount: 4,
    totalWeightLb: 2_800,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_without_dock",
    packagingType: "pallets_48x40",
    freightClass: "70",
    deliveryLiftgate: true,
  },
  {
    name: "Atlanta→Baltimore 住宅派送",
    pickupZip: "30326",
    deliveryZip: "21230",
    palletCount: 3,
    totalWeightLb: 1_200,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 60,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "residential",
    packagingType: "boxes",
    freightClass: "85",
    deliveryLiftgate: true,
    deliveryInside: true,
  },
  {
    name: "Boston→Chicago bags",
    pickupZip: "02109",
    deliveryZip: "60611",
    palletCount: 6,
    totalWeightLb: 5_500,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 72,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "bags",
    freightClass: "density",
    description: "papers",
    stackable: true,
    additionalServices: ["unloading"],
  },
  {
    name: "Dallas→Philly + 卸货服务",
    pickupZip: "75201",
    deliveryZip: "19106",
    palletCount: 8,
    totalWeightLb: 9_200,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 60,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "pallets_48x40",
    freightClass: "65",
    additionalServices: ["unloading"],
    vehicleTypes: ["box_truck", "dry_van"],
  },
  {
    name: "Austin→Denver crates",
    pickupZip: "78701",
    deliveryZip: "80202",
    palletCount: 2,
    totalWeightLb: 800,
    lengthIn: 48,
    widthIn: 48,
    heightIn: 48,
    pickupLocationType: "business_without_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "crates",
    freightClass: "100",
    pickupLiftgate: true,
    pickupPalletJack: true,
  },
  {
    name: "Seattle→Miami 大票",
    pickupZip: "98101",
    deliveryZip: "33130",
    palletCount: 10,
    totalWeightLb: 14_000,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 72,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "pallets_48x40",
    freightClass: "70",
    callBeforePickup: true,
  },
  {
    name: "Phoenix→Houston 无月台派送",
    pickupZip: "85004",
    deliveryZip: "77002",
    palletCount: 4,
    totalWeightLb: 3_200,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_without_dock",
    packagingType: "pallets_48x40",
    freightClass: "85",
    deliveryLiftgate: true,
    deliveryPalletJack: true,
  },
  {
    name: "Portland→Dallas 长托",
    pickupZip: "97201",
    deliveryZip: "75201",
    palletCount: 4,
    totalWeightLb: 8_000,
    lengthIn: 96,
    widthIn: 48,
    heightIn: 72,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "pallets_custom",
    freightClass: "density",
    turnable: true,
  },
  {
    name: "Denver→NYC drums",
    pickupZip: "80202",
    deliveryZip: "10001",
    palletCount: 5,
    totalWeightLb: 4_000,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "drums",
    freightClass: "92.5",
    description: "drums",
  },
  {
    name: "Chicago→Atlanta 学校派送",
    pickupZip: "60611",
    deliveryZip: "30326",
    palletCount: 3,
    totalWeightLb: 1_500,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "limited_school",
    packagingType: "boxes",
    freightClass: "110",
    deliveryLiftgate: true,
    deliveryInside: true,
    callBeforeDelivery: true,
  },
  {
    name: "BeverlyHills→Baltimore + load_to_ride",
    pickupZip: "90212",
    deliveryZip: "21230",
    palletCount: 6,
    totalWeightLb: 6_000,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 60,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "pallets_48x40",
    freightClass: "70",
    additionalServices: ["load_to_ride"],
    vehicleTypes: ["box_truck", "dry_van", "refrigerated"],
  },
  {
    name: "Philly→Boston 双侧无月台",
    pickupZip: "19106",
    deliveryZip: "02109",
    palletCount: 2,
    totalWeightLb: 700,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_without_dock",
    deliveryLocationType: "business_without_dock",
    packagingType: "pallets_48x40",
    freightClass: "85",
    pickupLiftgate: true,
    deliveryLiftgate: true,
  },
  {
    name: "Pittsburgh→LA 展会",
    pickupZip: "15222",
    deliveryZip: "90001",
    palletCount: 4,
    totalWeightLb: 2_400,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "trade_show",
    packagingType: "crates",
    freightClass: "125",
    deliveryPalletJack: true,
  },
  {
    name: "Houston→Seattle 48x48",
    pickupZip: "77002",
    deliveryZip: "98101",
    palletCount: 8,
    totalWeightLb: 12_000,
    lengthIn: 48,
    widthIn: 48,
    heightIn: 60,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "pallets_48x48",
    freightClass: "65",
    stackable: true,
  },
  {
    name: "Miami→Phoenix boxes",
    pickupZip: "33130",
    deliveryZip: "85004",
    palletCount: 2,
    totalWeightLb: 900,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "boxes",
    freightClass: "150",
    description: "cartons",
    turnable: false,
  },
  {
    name: "NYC→Dallas 住宅派送",
    pickupZip: "10001",
    deliveryZip: "75201",
    palletCount: 5,
    totalWeightLb: 3_500,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "residential",
    packagingType: "boxes",
    freightClass: "70",
    deliveryLiftgate: true,
    deliveryInside: true,
  },
  {
    name: "SF→Austin + 预约前电联",
    pickupZip: "94102",
    deliveryZip: "78701",
    palletCount: 3,
    totalWeightLb: 1_800,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "residential",
    deliveryLocationType: "business_with_dock",
    packagingType: "boxes",
    freightClass: "92.5",
    pickupLiftgate: true,
    pickupInside: true,
    callBeforePickup: true,
    callBeforeDelivery: true,
    readyOffsetDays: 1,
  },
  {
    name: "Baltimore→Gardena coils",
    pickupZip: "21230",
    deliveryZip: "90248",
    palletCount: 4,
    totalWeightLb: 6_500,
    lengthIn: 48,
    widthIn: 40,
    heightIn: 48,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "coils",
    freightClass: "60",
    additionalServices: ["unloading"],
  },
  {
    name: "Chicago→Denver 轻货偏移日",
    pickupZip: "60611",
    deliveryZip: "80202",
    palletCount: 2,
    totalWeightLb: 600,
    lengthIn: 40,
    widthIn: 36,
    heightIn: 36,
    pickupLocationType: "business_with_dock",
    deliveryLocationType: "business_with_dock",
    packagingType: "boxes",
    freightClass: "density",
    stackable: true,
    additionalServices: ["unloading"],
    readyOffsetDays: 2,
  },
];

function offsetPickupIso(baseIso: string, offsetDays: number): string {
  if (!offsetDays) return baseIso;
  const [y, m, d] = baseIso.split("-").map(Number);
  const dt = new Date(y!, m! - 1, d!);
  let left = offsetDays;
  while (left > 0) {
    dt.setDate(dt.getDate() + 1);
    const iso = toIsoDateLocal(dt);
    if (!isMothershipWeekendIso(iso)) left -= 1;
  }
  return snapMothershipReadyDateToWeekday(toIsoDateLocal(dt));
}

function sleep(ms: number): Promise<void> {
  return new Promise((r) => setTimeout(r, ms));
}

type Row = {
  n: number;
  name: string;
  ok: boolean;
  ms: number;
  tiers: number;
  detail: string;
  code?: string;
};

function assertCasesValid(cases: CaseDef[]): void {
  for (const c of cases) {
    if (c.palletCount < 1) throw new Error(`case ${c.name}: palletCount`);
    if (c.totalWeightLb > 45_000) throw new Error(`case ${c.name}: weight`);
    if (c.pickupZip === c.deliveryZip) {
      throw new Error(`case ${c.name}: same zip`);
    }
    if (
      !fitsFlockTrailerCargo({
        palletCount: c.palletCount,
        lengthIn: c.lengthIn,
        widthIn: c.widthIn,
      })
    ) {
      throw new Error(`case ${c.name}: linear feet`);
    }
  }
}

async function main(): Promise<void> {
  assertCasesValid(FLOCK_LOGGED_IN_X20_CASES);

  const onlyRaw = process.env.DIAG_ONLY?.trim() ?? "";
  const onlyNums = onlyRaw
    ? onlyRaw
        .split(/[,，\s]+/)
        .map((s) => s.trim())
        .filter((s) => /^\d+$/.test(s))
        .map(Number)
    : [];
  const selected = FLOCK_LOGGED_IN_X20_CASES.map((c, i) => ({ c, n: i })).filter(
    ({ c, n }) => {
      if (!onlyRaw) return true;
      if (onlyNums.length > 0) return onlyNums.includes(n + 1);
      return c.name.includes(onlyRaw);
    },
  );
  if (selected.length === 0) {
    throw new Error(`DIAG_ONLY=${onlyRaw} 无匹配用例`);
  }

  const customerId = process.env.DIAG_CUSTOMER_ID?.trim() || "CUST_001";
  const login = await getCustomerProviderLogin(customerId, "flock");
  if (!login) {
    throw new Error(`客户 ${customerId} 无可用 Flock 账密`);
  }

  console.log("=== Flock Freight 登录态 ×20 多线路探测 ===");
  console.log(
    `headed=${wantHeaded} customer=${customerId} email=${login.email.slice(0, 2)}*** ` +
      `pickupBase=${PICKUP_BASE} cases=${selected.length}/${FLOCK_LOGGED_IN_X20_CASES.length}` +
      (onlyRaw ? ` only=${onlyRaw}` : "") +
      ` delayMs=${DELAY_MS}`,
  );

  const rows: Row[] = [];
  for (let i = 0; i < selected.length; i += 1) {
    const { c, n } = selected[i]!;
    if (i > 0 && DELAY_MS > 0) await sleep(DELAY_MS);

    const pickupIso = offsetPickupIso(PICKUP_BASE, c.readyOffsetDays ?? 0);
    const pickupDate = flockPickupDisplayFromIso(pickupIso);
    const t0 = Date.now();
    console.log(
      `\n---------- ${n + 1}/20 ${c.name} ${c.pickupZip}→${c.deliveryZip} ` +
        `${c.palletCount}pl ${c.totalWeightLb}lb ----------`,
    );
    console.log(
      `  loc=${c.pickupLocationType}/${c.deliveryLocationType} pack=${c.packagingType} ` +
        `svc=[${(c.additionalServices ?? []).join(",")}] date=${pickupDate}`,
    );

    const input: FlockQuoteInput = {
      formMode: "logged_in_quick",
      pickupDate,
      pickupZip: c.pickupZip,
      deliveryZip: c.deliveryZip,
      palletCount: c.palletCount,
      totalWeightLb: c.totalWeightLb,
      lengthIn: c.lengthIn,
      widthIn: c.widthIn,
      heightIn: c.heightIn,
      pickupLocationType: c.pickupLocationType,
      deliveryLocationType: c.deliveryLocationType,
      packagingType: c.packagingType,
      freightClass: c.freightClass,
      description: c.description,
      stackable: c.stackable,
      turnable: c.turnable,
      additionalServices: c.additionalServices,
      vehicleTypes: c.vehicleTypes,
      pickupLiftgate: c.pickupLiftgate,
      pickupInside: c.pickupInside,
      pickupPalletJack: c.pickupPalletJack,
      deliveryLiftgate: c.deliveryLiftgate,
      deliveryInside: c.deliveryInside,
      deliveryPalletJack: c.deliveryPalletJack,
      callBeforePickup: c.callBeforePickup,
      callBeforeDelivery: c.callBeforeDelivery,
    };

    const result = await runFlockQuoteRpa(input, { customerId });
    const ms = Date.now() - t0;
    if (result.ok && result.quotes.length > 0) {
      const preview = result.quotes
        .slice(0, 4)
        .map((q) => `${q.label}=$${q.totalUsd}`)
        .join(", ");
      rows.push({
        n: n + 1,
        name: c.name,
        ok: true,
        ms,
        tiers: result.quotes.length,
        detail: `${result.quotes.length}档 ${preview}${result.quotes.length > 4 ? "…" : ""}`,
      });
      console.log(`[OK] ${ms}ms tiers=${result.quotes.length} ${preview}`);
    } else {
      const msg = (result.errorMessage ?? "no quotes").slice(0, 240);
      const codeMatch = /^([A-Z][A-Z0-9_]+)：/.exec(msg);
      rows.push({
        n: n + 1,
        name: c.name,
        ok: false,
        ms,
        tiers: 0,
        detail: msg,
        code: codeMatch?.[1],
      });
      console.log(`[FAIL] ${ms}ms ${msg.slice(0, 180)}`);
    }
  }

  const okN = rows.filter((r) => r.ok).length;
  const failN = rows.length - okN;
  const avgOkMs =
    okN > 0
      ? Math.round(
          rows.filter((r) => r.ok).reduce((s, r) => s + r.ms, 0) / okN,
        )
      : 0;

  const outDir = path.join(process.cwd(), ".rpa", "diag");
  fs.mkdirSync(outDir, { recursive: true });
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
  const reportPath = path.join(outDir, `flock-logged-in-x20-${stamp}.md`);
  const lines = [
    `# Flock Freight 登录态 ×20`,
    ``,
    `- customer: ${customerId}`,
    `- pickupBase: ${PICKUP_BASE}`,
    `- ok=${okN} fail=${failN} avgOkMs=${avgOkMs}`,
    ``,
    `| # | 结果 | 用例 | ms | tiers | 详情 |`,
    `|---|------|------|----|-------|------|`,
    ...rows.map(
      (r) =>
        `| ${r.n} | ${r.ok ? "OK" : "FAIL"} | ${r.name} | ${r.ms} | ${r.tiers} | ${(r.code ? `[${r.code}] ` : "") + r.detail.replace(/\|/g, "/")} |`,
    ),
  ];
  fs.writeFileSync(reportPath, lines.join("\n"), "utf8");

  console.log(
    `\n=== SUMMARY ok=${okN}/${FLOCK_LOGGED_IN_X20_CASES.length} fail=${failN} avgOkMs=${avgOkMs} ===`,
  );
  console.log(`report=${reportPath}`);
  for (const r of rows) {
    console.log(
      `  #${r.n} ${r.ok ? "OK  " : "FAIL"} ${r.name} ${r.ms}ms tiers=${r.tiers}` +
        (r.ok ? "" : ` [${r.code ?? "-"}]`),
    );
  }

  if (failN > 0) process.exitCode = 1;
}

const isDirectRun =
  typeof process.argv[1] === "string" &&
  /diag-flock-logged-in-x20\.(ts|js|mts|mjs)$/i.test(
    process.argv[1].replace(/\\/g, "/"),
  );

if (isDirectRun) {
  main().catch((err) => {
    console.error(err);
    process.exit(1);
  });
}