/**
 * Flock 登录后查价表单（Let's build a quote / Quick）
 * 与匿名 marketing lead 表单字段不同，需单独填写必填下拉项
 */
import type { Page } from "playwright";
import { getFlockFieldPauseMs } from "@/lib/flock/env";
import { gotoWithResilience } from "@/lib/rpa/page-goto";
import {
  flockFreightClassRpaLabels,
  flockLocationRpaLabels,
  flockPackagingRpaLabels,
  FLOCK_DEFAULT_VEHICLE_IDS,
  FLOCK_DELIVERY_SERVICE_RPA_LABELS,
  FLOCK_DELIVERY_SERVICE_WEIGHT_LOCKED,
  FLOCK_PICKUP_SERVICE_RPA_LABELS,
  FLOCK_PICKUP_SERVICE_WEIGHT_LOCKED,
  FLOCK_SERVICE_RPA_LABELS,
  FLOCK_VEHICLE_RPA_LABELS,
} from "@/lib/flock/logged-in-rpa-options";
import { FLOCK_LIMITS } from "@/lib/constants/flock-limits";
import { FLOCK_LOCATION_ACCESSORIALS } from "@/components/flock/flock-logged-in-quote-form";
import type { FlockQuoteInput } from "@/workers/rpa/flock/types";
import {
  flockLocatorCount,
  flockPageClosedMessage,
  isFlockPageClosedError,
} from "@/workers/rpa/flock/page-alive";

const FIELD_WAIT_MS = 20_000;
const DEFAULT_DESCRIPTION = "General freight";

function pauseMs(): number {
  return getFlockFieldPauseMs();
}

async function pause(page: Page): Promise<void> {
  const ms = pauseMs();
  if (ms > 0) {
    await page.waitForTimeout(ms);
  }
}

/** 是否为登录后 Quick 查价页 */
export async function isFlockLoggedInQuoteForm(page: Page): Promise<boolean> {
  const markers = [
    page.getByTestId("quote-request-quick-form__submit_button"),
    page.getByTestId("quick-form-toggle"),
    page.getByRole("heading", { name: /Let'?s build a quote/i }),
    page.getByText(/Shipment Pickup/i).first(),
    page.getByRole("textbox", { name: /Quantity/i }),
    page.getByRole("combobox", { name: /Freight Class/i }),
    page.getByRole("combobox", { name: /Packaging Type/i }),
    page.getByRole("button", { name: /Generate my quote/i }),
  ];
  for (const loc of markers) {
    if (
      (await flockLocatorCount(loc)) > 0 &&
      (await loc.first().isVisible().catch(() => false))
    ) {
      return true;
    }
  }
  return false;
}

/**
 * 登录后打开 Quick 查价（录制：home → + New quote → Quick）
 * 截图可见主按钮文案为「 New quote」；testid 可能缺失，必须按可见文案点
 */
export async function openFlockLoggedInQuoteEntry(page: Page): Promise<boolean> {
  if (await isFlockLoggedInQuoteForm(page)) {
    return true;
  }

  const homeUrl =
    process.env.FLOCK_LOGGED_IN_HOME_URL?.trim() ||
    "https://app.flockfreight.com/home";
  if (!/\/home(?:\/|$|\?)/i.test(page.url())) {
    await gotoWithResilience(page, homeUrl);
  }

  // 等 dashboard 主 CTA 出现（慢网 / hydration）
  await page
    .getByRole("button", { name: /New quote/i })
    .or(page.getByTestId("header-new-quote-button"))
    .first()
    .waitFor({ state: "visible", timeout: 20_000 })
    .catch(() => undefined);

  const newQuoteLocators = [
    page.getByTestId("header-new-quote-button"),
    page.locator('button:has-text("New quote")'),
    page.locator('a:has-text("New quote")'),
    page.getByRole("button", { name: /New quote/i }),
    page.getByRole("link", { name: /New quote/i }),
    page.getByRole("link", { name: /Request Quote/i }),
  ];

  let clickedNew = false;
  for (const loc of newQuoteLocators) {
    const target = loc.first();
    const n = await flockLocatorCount(target);
    if (n === 0) continue;
    const visible = await target.isVisible().catch(() => false);
    console.log(`[flock-form] New quote candidate count=${n}`);
    if (!visible) continue;
    try {
      await target.scrollIntoViewIfNeeded().catch(() => undefined);
      await target.click({ timeout: 5_000 });
      clickedNew = true;
      console.log("[flock-login] 已点击 New quote");
      break;
    } catch (err) {
      const msg = err instanceof Error ? err.message : String(err);
      console.warn(`[flock-login] New quote 普通点击失败，改 force: ${msg.slice(0, 80)}`);
      try {
        await target.click({ force: true, timeout: 5_000 });
        clickedNew = true;
        console.log("[flock-login] 已 force 点击 New quote");
        break;
      } catch (err2) {
        console.warn(
          `[flock-login] force 点击仍失败: ${
            err2 instanceof Error ? err2.message.slice(0, 80) : err2
          }`,
        );
      }
    }
  }

  if (!clickedNew) {
    console.warn("[flock-login] 未点到 New quote，尝试顶栏 Request Quote");
    const req = page.getByRole("link", { name: /^Request Quote$/i }).first();
    if (await req.isVisible().catch(() => false)) {
      await req.click({ force: true }).catch(() => undefined);
      clickedNew = true;
    }
  }

  await page.waitForTimeout(1_000);

  const quickCandidates = [
    page.getByTestId("quick-form-toggle"),
    page.getByRole("button", { name: /^Quick$/i }),
    page.getByRole("tab", { name: /^Quick$/i }),
  ];
  for (const loc of quickCandidates) {
    const target = loc.first();
    if (await target.isVisible({ timeout: 4_000 }).catch(() => false)) {
      await target.click({ force: true }).catch(() => undefined);
      console.log("[flock-login] 已切 Quick");
      await page.waitForTimeout(800);
      break;
    }
  }

  const deadline = Date.now() + 20_000;
  while (Date.now() < deadline) {
    if (await isFlockLoggedInQuoteForm(page)) {
      return true;
    }
    await page.waitForTimeout(400);
  }

  return isFlockLoggedInQuoteForm(page);
}

async function fillTextbox(
  page: Page,
  names: Array<string | RegExp>,
  value: string,
): Promise<boolean> {
  for (const name of names) {
    const loc = page.getByRole("textbox", { name }).first();
    try {
      await loc.waitFor({ state: "visible", timeout: FIELD_WAIT_MS });
      await loc.click({ clickCount: 3 }).catch(() => undefined);
      await loc.fill(value);
      return true;
    } catch (error) {
      if (isFlockPageClosedError(error)) throw error;
      continue;
    }
  }
  return false;
}

async function fillTextarea(
  page: Page,
  names: Array<string | RegExp>,
  value: string,
): Promise<boolean> {
  for (const name of names) {
    const byRole = page.getByRole("textbox", { name }).first();
    if ((await flockLocatorCount(byRole)) > 0) {
      try {
        await byRole.waitFor({ state: "visible", timeout: FIELD_WAIT_MS });
        await byRole.fill(value);
        return true;
      } catch {
        /* try label */
      }
    }
    const byLabel = page.getByLabel(name).first();
    if ((await flockLocatorCount(byLabel)) > 0) {
      try {
        await byLabel.fill(value);
        return true;
      } catch {
        continue;
      }
    }
  }
  return false;
}

/** 打开 combobox / 下拉，按候选精确或包含匹配；禁止误点第一项 */
export async function selectFlockComboboxOption(
  page: Page,
  fieldName: RegExp,
  optionCandidates: string[],
): Promise<boolean> {
  const combo = page.getByRole("combobox", { name: fieldName }).first();
  const button = page.getByRole("button", { name: fieldName }).first();
  const trigger =
    (await flockLocatorCount(combo)) > 0
      ? combo
      : (await flockLocatorCount(button)) > 0
        ? button
        : null;
  if (!trigger) {
    return false;
  }

  await trigger.click({ force: true });
  await page.waitForTimeout(400);

  // 等下拉 option 出现（MUI listbox 可能晚于 click）
  await page
    .getByRole("option")
    .first()
    .waitFor({ state: "attached", timeout: 4_000 })
    .catch(() => undefined);
  await page.waitForTimeout(200);

  const normalize = (s: string) =>
    s
      .toLowerCase()
      .replace(/[–—−]/g, "-")
      .replace(/\s+/g, " ")
      .replace(/[^\w\s/-]/g, "")
      .trim();

  async function collectOptionTexts(): Promise<
    Array<{ index: number; text: string }>
  > {
    const seen = new Set<string>();
    const rows: Array<{ index: number; text: string }> = [];
    // 虚拟列表：方向键滚动加载
    for (let i = 0; i < 40; i++) {
      const options = page.getByRole("option");
      const n = await flockLocatorCount(options);
      for (let j = 0; j < n; j++) {
        const opt = options.nth(j);
        const raw = ((await opt.innerText().catch(() => "")) || "")
          .replace(/\s+/g, " ")
          .trim();
        if (!raw || seen.has(raw)) continue;
        seen.add(raw);
        rows.push({ index: j, text: raw });
      }
      await page.keyboard.press("ArrowDown").catch(() => undefined);
      await page.waitForTimeout(40);
    }
    return rows;
  }

  async function clickMatchingOption(candidate: string): Promise<boolean> {
    const exact = page
      .getByRole("option", {
        name: new RegExp(`^${escapeRe(candidate)}$`, "i"),
      })
      .first();
    if ((await flockLocatorCount(exact)) > 0) {
      await exact.scrollIntoViewIfNeeded().catch(() => undefined);
      await exact.click({ force: true });
      return true;
    }
    const loose = page.getByRole("option", { name: candidate }).first();
    if ((await flockLocatorCount(loose)) > 0) {
      await loose.scrollIntoViewIfNeeded().catch(() => undefined);
      await loose.click({ force: true });
      return true;
    }
    // 含匹配（Limited Access – Airport 等）
    const contains = page
      .getByRole("option", {
        name: new RegExp(escapeRe(candidate), "i"),
      })
      .first();
    if ((await flockLocatorCount(contains)) > 0) {
      await contains.scrollIntoViewIfNeeded().catch(() => undefined);
      await contains.click({ force: true });
      return true;
    }
    return false;
  }

  // 1) 直接按候选点
  for (const candidate of optionCandidates) {
    if (await clickMatchingOption(candidate)) return true;
  }

  // 2) 输入过滤（MUI Autocomplete）再点
  for (const candidate of optionCandidates) {
    const filterKey = candidate.replace(/^Limited Access\s*[-–]\s*/i, "").trim();
    if (filterKey.length < 2) continue;
    await trigger.click({ force: true }).catch(() => undefined);
    await page.keyboard.press("Control+A").catch(() => undefined);
    await page.keyboard.type(filterKey.slice(0, 24), { delay: 20 }).catch(() => undefined);
    await page.waitForTimeout(350);
    if (await clickMatchingOption(candidate)) return true;
    if (await clickMatchingOption(filterKey)) return true;
    await page.keyboard.press("Escape").catch(() => undefined);
    await page.waitForTimeout(200);
    await trigger.click({ force: true }).catch(() => undefined);
    await page.waitForTimeout(300);
  }

  // 3) 收集全部 option 文本后模糊匹配
  await trigger.click({ force: true }).catch(() => undefined);
  await page.waitForTimeout(300);
  const rows = await collectOptionTexts();
  const wantNorms = optionCandidates.map(normalize);
  const hit = rows.find((row) => {
    const n = normalize(row.text);
    return wantNorms.some(
      (w) => n === w || n.includes(w) || w.includes(n) || n.endsWith(w),
    );
  });
  if (hit) {
    const opt = page.getByRole("option", { name: hit.text }).first();
    if ((await flockLocatorCount(opt)) > 0) {
      await opt.scrollIntoViewIfNeeded().catch(() => undefined);
      await opt.click({ force: true });
      return true;
    }
    // 虚拟列表：再用键盘定位
    await page.keyboard.press("Home").catch(() => undefined);
    for (let i = 0; i < rows.length + 5; i++) {
      const focused = page.locator('[role="option"][aria-selected="true"], [role="option"].Mui-focused').first();
      const t = ((await focused.innerText().catch(() => "")) || "").trim();
      if (t && normalize(t) === normalize(hit.text)) {
        await page.keyboard.press("Enter");
        return true;
      }
      await page.keyboard.press("ArrowDown").catch(() => undefined);
      await page.waitForTimeout(40);
    }
  }

  console.warn(
    `[flock-form] combobox 未匹配: field=${fieldName} candidates=${optionCandidates.join("|")} visible=[${rows.map((r) => r.text).slice(0, 20).join(" | ")}]`,
  );
  await page.keyboard.press("Escape").catch(() => undefined);
  return false;
}

function escapeRe(value: string): string {
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

/** 登录后日期：Shipment Pickup + Choose date */
export async function fillLoggedInPickupDate(
  page: Page,
  pickupDateDisplay: string,
): Promise<boolean> {
  const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(pickupDateDisplay.trim());
  const dayRaw = m?.[2];
  const dayNum = dayRaw ? String(Number(dayRaw)) : null;

  const openers = [
    page.getByRole("button", { name: /Choose date|选择日期/i }).first(),
    page.getByLabel(/Shipment Pickup/i).first(),
    page.getByRole("textbox", { name: /Shipment Pickup|Pickup Date/i }).first(),
  ];

  for (const opener of openers) {
    if ((await flockLocatorCount(opener)) === 0) continue;
    await opener.click().catch(() => undefined);
    await page.waitForTimeout(400);
    if (!dayNum || !dayRaw) break;
    for (const dayLabel of [dayNum, dayRaw]) {
      const cell = page.getByRole("gridcell", { name: dayLabel }).first();
      if ((await flockLocatorCount(cell)) > 0) {
        await cell.click();
        return true;
      }
    }
  }

  return fillTextbox(
    page,
    [/Shipment Pickup/i, /Pickup Date/i],
    pickupDateDisplay,
  );
}

/** 确保 Quick 模式（非 Guided 分步） */
async function ensureQuickMode(page: Page): Promise<void> {
  const quick = page.getByRole("button", { name: /^Quick$/i }).first();
  if ((await flockLocatorCount(quick)) === 0) return;
  const pressed = await quick.getAttribute("aria-pressed").catch(() => null);
  const selected = await quick.getAttribute("aria-selected").catch(() => null);
  if (pressed === "true" || selected === "true") return;
  await quick.click().catch(() => undefined);
  await page.waitForTimeout(500);
}

export type LoggedInFormInput = Pick<
  FlockQuoteInput,
  | "pickupDate"
  | "pickupZip"
  | "deliveryZip"
  | "palletCount"
  | "totalWeightLb"
  | "lengthIn"
  | "widthIn"
  | "heightIn"
  | "pickupLocationType"
  | "deliveryLocationType"
  | "packagingType"
  | "freightClass"
  | "description"
  | "stackable"
  | "turnable"
  | "additionalServices"
  | "vehicleTypes"
  | "callBeforePickup"
  | "callBeforeDelivery"
  | "pickupLiftgate"
  | "pickupInside"
  | "pickupPalletJack"
  | "deliveryLiftgate"
  | "deliveryInside"
  | "deliveryPalletJack"
  | "pickupService"
  | "deliveryService"
  | "pickupWindowStartTime"
  | "pickupWindowEndTime"
  | "pickupAppointmentTime"
  | "deliveryWindowStartTime"
  | "deliveryWindowEndTime"
  | "deliveryWindowDate"
  | "deliveryAppointmentTime"
  | "deliveryAppointmentDate"
  | "deliveryMustArriveByDate"
  | "callForDeliveryAppointment"
>;

async function setCheckbox(
  page: Page,
  name: RegExp,
  checked: boolean,
  index = 0,
): Promise<boolean> {
  const box = page.getByRole("checkbox", { name }).nth(index);
  if ((await flockLocatorCount(box)) === 0) return false;
  const isChecked = await box.isChecked().catch(() => false);
  if (isChecked === checked) return true;
  await box.click({ force: true });
  await page.waitForTimeout(200);
  const after = await box.isChecked().catch(() => !checked);
  return after === checked;
}

/** 按官网可见文案勾选地点附属项（含 wait + 重试） */
async function ensureLabeledCheckbox(
  page: Page,
  labelCandidates: string[],
  checked: boolean,
): Promise<boolean> {
  for (const text of labelCandidates) {
    const byRole = page
      .getByRole("checkbox", { name: new RegExp(escapeRe(text), "i") })
      .first();
    const input = page
      .locator("label")
      .filter({ hasText: new RegExp(escapeRe(text), "i") })
      .locator('input[type="checkbox"]')
      .first();

    for (const loc of [byRole, input]) {
      try {
        await loc.waitFor({ state: "visible", timeout: 3_000 });
      } catch {
        continue;
      }
      for (let attempt = 0; attempt < 3; attempt++) {
        const on = await loc.isChecked().catch(() => false);
        if (on === checked) return true;
        try {
          if (checked) await loc.check({ force: true, timeout: 2_000 });
          else await loc.uncheck({ force: true, timeout: 2_000 });
        } catch {
          await loc.click({ force: true }).catch(() => undefined);
        }
        await page.waitForTimeout(250);
        const after = await loc.isChecked().catch(() => on);
        if (after === checked) return true;
      }
    }
  }
  return false;
}

function locationAccessorialFlags(typeId?: string): {
  liftgate: boolean;
  inside: boolean;
  palletJack: boolean;
} | null {
  if (!typeId) return null;
  return (
    FLOCK_LOCATION_ACCESSORIALS[
      typeId as keyof typeof FLOCK_LOCATION_ACCESSORIALS
    ] ?? null
  );
}

/** 地点类型附属勾选项（对齐官网文案：Liftgate Required for Pickup 等） */
async function applyLoggedInLocationAccessorials(
  page: Page,
  input: LoggedInFormInput,
): Promise<void> {
  // 等 Type 切换后附属行渲染
  await page.waitForTimeout(800);

  const PALLET_LABELS = [
    "Location has Pallet Jack and Forklift",
    "Location equipped with pallet jack and forklift",
  ];

  const pickupFlags = locationAccessorialFlags(input.pickupLocationType);
  const deliveryFlags = locationAccessorialFlags(input.deliveryLocationType);

  // 仅当类型矩阵声明存在该附属项时才操作，避免住宅无 Pallet 时误动派送侧同名框
  if (pickupFlags?.liftgate && typeof input.pickupLiftgate === "boolean") {
    await ensureLabeledCheckbox(
      page,
      ["Liftgate Required for Pickup"],
      input.pickupLiftgate,
    );
  }
  if (pickupFlags?.inside && typeof input.pickupInside === "boolean") {
    await ensureLabeledCheckbox(page, ["Inside Pickup"], input.pickupInside);
  }
  if (pickupFlags?.palletJack && typeof input.pickupPalletJack === "boolean") {
    const ok = await ensureLabeledCheckbox(
      page,
      PALLET_LABELS,
      input.pickupPalletJack,
    );
    if (!ok && input.pickupPalletJack) {
      console.warn("[flock-form] Pickup Pallet Jack 勾选失败");
    }
  }

  if (deliveryFlags?.liftgate && typeof input.deliveryLiftgate === "boolean") {
    await ensureLabeledCheckbox(
      page,
      ["Liftgate Required for Delivery"],
      input.deliveryLiftgate,
    );
  }
  if (deliveryFlags?.inside && typeof input.deliveryInside === "boolean") {
    await ensureLabeledCheckbox(
      page,
      ["Inside Delivery"],
      input.deliveryInside,
    );
  }
  if (
    deliveryFlags?.palletJack &&
    typeof input.deliveryPalletJack === "boolean"
  ) {
    const pallets = page.getByRole("checkbox", {
      name: /Location has Pallet Jack and Forklift/i,
    });
    const n = await flockLocatorCount(pallets);
    const box =
      n > 1 && pickupFlags?.palletJack ? pallets.nth(1) : pallets.first();
    if (n > 0) {
      for (let attempt = 0; attempt < 3; attempt++) {
        const on = await box.isChecked().catch(() => false);
        if (on === input.deliveryPalletJack) break;
        try {
          if (input.deliveryPalletJack) {
            await box.check({ force: true });
          } else {
            await box.uncheck({ force: true });
          }
        } catch {
          await box.click({ force: true }).catch(() => undefined);
        }
        await page.waitForTimeout(250);
      }
    } else {
      await ensureLabeledCheckbox(
        page,
        PALLET_LABELS,
        input.deliveryPalletJack,
      );
    }
  }
}

/**
 * Options: Stackable / Turnable
 * 禁止「勾 checkbox 再点文案」——会二次切换把已选取消
 */
async function ensureOptionToggle(
  page: Page,
  label: "Stackable" | "Turnable",
  wantOn: boolean,
): Promise<void> {
  const byRole = page
    .getByRole("checkbox", { name: new RegExp(`^${label}$`, "i") })
    .first();
  if ((await flockLocatorCount(byRole)) > 0) {
    const on = await byRole.isChecked().catch(() => false);
    if (on === wantOn) {
      console.log(`[flock-form] Options ${label} 已是目标态，跳过`);
      return;
    }
    await byRole.click({ force: true });
    await page.waitForTimeout(250);
    const after = await byRole.isChecked().catch(() => on);
    console.log(`[flock-form] Options ${label} -> ${after ? "on" : "off"}`);
    if (after !== wantOn) {
      await byRole.click({ force: true });
      await page.waitForTimeout(200);
    }
    return;
  }

  const labelLoc = page.getByText(new RegExp(`^${label}$`, "i")).first();
  if (!(await labelLoc.isVisible().catch(() => false))) return;
  const inputNear = page
    .locator(
      `label:has-text("${label}") input[type="checkbox"], input[type="checkbox"][name*="${label}" i]`,
    )
    .first();
  const before =
    (await flockLocatorCount(inputNear)) > 0
      ? await inputNear.isChecked().catch(() => false)
      : false;
  if (before === wantOn) {
    console.log(`[flock-form] Options ${label}(label) 已是目标态，跳过`);
    return;
  }
  await labelLoc.click({ force: true });
  await page.waitForTimeout(250);
  console.log(`[flock-form] Options ${label}(label) toggled`);
}

/** MUI chip：以 CheckCircle / aria-pressed 为准（勿用 outlined/svg 误判） */
async function isChipSelected(
  loc: import("playwright").Locator,
): Promise<boolean> {
  return loc.evaluate((el) => {
    const aria =
      el.getAttribute("aria-pressed") ?? el.getAttribute("aria-checked");
    if (aria === "true") return true;
    if (aria === "false") return false;
    if (
      el.querySelector(
        '[data-testid="CheckCircleIcon"], [data-testid="CheckIcon"], [data-testid="DoneIcon"]',
      )
    ) {
      return true;
    }
    for (const svg of Array.from(el.querySelectorAll("svg"))) {
      const tip =
        (svg.getAttribute("data-testid") || "") +
        " " +
        (svg.getAttribute("class") || "");
      if (/CheckCircle|CheckIcon|DoneIcon/i.test(tip)) return true;
    }
    return el.classList.contains("Mui-selected");
  });
}

async function ensureChip(
  page: Page,
  label: string,
  wantOn: boolean,
): Promise<"ok" | "skipped" | "toggled"> {
  const btn = page.getByRole("button", { name: label }).first();
  if (!(await btn.isVisible({ timeout: 2_000 }).catch(() => false))) {
    console.warn(`[flock-form] 芯片不可见: ${label}`);
    return "skipped";
  }
  const on = await isChipSelected(btn);
  if (on === wantOn) return "ok";
  await btn.click({ force: true });
  await page.waitForTimeout(350);
  const after = await isChipSelected(btn);
  console.log(
    `[flock-form] 芯片 ${label}: ${on ? "开" : "关"}→${wantOn ? "开" : "关"} 实测=${after ? "开" : "关"}`,
  );
  return "toggled";
}

function isDefaultVehicleSet(ids: string[]): boolean {
  const want = new Set<string>(FLOCK_DEFAULT_VEHICLE_IDS);
  const got = new Set(ids.map((s) => s.trim()).filter(Boolean));
  if (want.size !== got.size) return false;
  for (const id of want) {
    if (!got.has(id)) return false;
  }
  return true;
}

function toUsDateDisplay(raw: string): string {
  const t = raw.trim();
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(t);
  if (m) return `${m[2]}/${m[3]}/${m[1]}`;
  return t;
}

function schedulingWeightUnlocked(totalWeightLb: number): boolean {
  return (
    Number.isFinite(totalWeightLb) &&
    totalWeightLb > FLOCK_LIMITS.schedulingWeightMinLb
  );
}

async function selectSchedulingRadio(
  page: Page,
  candidates: readonly string[],
): Promise<boolean> {
  for (const label of candidates) {
    const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    const radio = page
      .getByRole("radio", { name: new RegExp(escaped, "i") })
      .first();
    if ((await flockLocatorCount(radio)) === 0) continue;
    if (await radio.isDisabled().catch(() => true)) {
      console.log(`[flock-form] 调度 radio 禁用跳过: ${label}`);
      continue;
    }
    const on = await radio.isChecked().catch(() => false);
    if (on) return true;
    try {
      await radio.scrollIntoViewIfNeeded().catch(() => undefined);
      // 官网自定义 radio 偶发不可点；短超时 + force，失败再试 label
      await radio.click({ force: true, timeout: 5_000 });
      await page.waitForTimeout(300);
      return true;
    } catch {
      const lbl = page
        .locator("label")
        .filter({ hasText: new RegExp(escaped, "i") })
        .first();
      if ((await flockLocatorCount(lbl)) > 0) {
        const clicked = await lbl
          .click({ force: true, timeout: 5_000 })
          .then(() => true)
          .catch(() => false);
        if (clicked) {
          await page.waitForTimeout(300);
          return true;
        }
      }
      console.warn(`[flock-form] 调度 radio 点击失败，跳过: ${label}`);
    }
  }
  return false;
}

async function fillSchedulingTimeField(
  page: Page,
  fieldName: RegExp,
  value: string,
): Promise<boolean> {
  if (!value.trim()) return false;
  if (await selectFlockComboboxOption(page, fieldName, [value, value.trim()])) {
    return true;
  }
  // 部分页面 Time 为 native select / textbox
  const combo = page.getByRole("combobox", { name: fieldName }).first();
  if ((await flockLocatorCount(combo)) > 0) {
    await combo.click({ force: true }).catch(() => undefined);
    await page.waitForTimeout(200);
    const opt = page.getByRole("option", { name: value }).first();
    if ((await flockLocatorCount(opt)) > 0) {
      await opt.click({ force: true });
      return true;
    }
  }
  const box = page.getByRole("textbox", { name: fieldName }).first();
  if ((await flockLocatorCount(box)) > 0) {
    await box.fill(value).catch(() => undefined);
    return true;
  }
  return false;
}

async function fillSchedulingDateField(
  page: Page,
  fieldName: RegExp,
  value: string,
): Promise<boolean> {
  const display = toUsDateDisplay(value);
  if (!display) return false;
  const box = page.getByRole("textbox", { name: fieldName }).first();
  if ((await flockLocatorCount(box)) > 0) {
    await box.click({ force: true }).catch(() => undefined);
    await box.fill("").catch(() => undefined);
    await box.fill(display).catch(() => undefined);
    await page.keyboard.press("Tab").catch(() => undefined);
    return true;
  }
  return selectFlockComboboxOption(page, fieldName, [display, value]);
}

/** 调度服务（总重 >5000 启用灰色项）+ 下级时间/日期 */
async function applyLoggedInScheduling(
  page: Page,
  input: LoggedInFormInput,
): Promise<void> {
  const section = page
    .getByRole("button", { name: /Scheduling Services/i })
    .first();
  if (await section.isVisible().catch(() => false)) {
    await section.click().catch(() => undefined);
    await page.waitForTimeout(350);
  }

  const weightOk = schedulingWeightUnlocked(input.totalWeightLb);
  let pickupService = (input.pickupService ?? "standard_fcfs").trim();
  let deliveryService = (input.deliveryService ?? "standard_fcfs").trim();

  if (
    FLOCK_PICKUP_SERVICE_WEIGHT_LOCKED[pickupService] &&
    !weightOk
  ) {
    console.log(
      `[flock-form] 提货调度 ${pickupService} 需总重>${FLOCK_LIMITS.schedulingWeightMinLb}，回退 standard_fcfs`,
    );
    pickupService = "standard_fcfs";
  }
  if (
    FLOCK_DELIVERY_SERVICE_WEIGHT_LOCKED[deliveryService] &&
    !weightOk
  ) {
    console.log(
      `[flock-form] 派送调度 ${deliveryService} 需总重>${FLOCK_LIMITS.schedulingWeightMinLb}，回退 standard_fcfs`,
    );
    deliveryService = "standard_fcfs";
  }

  const pickupLabels =
    FLOCK_PICKUP_SERVICE_RPA_LABELS[pickupService] ??
    FLOCK_PICKUP_SERVICE_RPA_LABELS.standard_fcfs;
  if (!(await selectSchedulingRadio(page, pickupLabels!))) {
    console.warn(`[flock-form] 未选中提货调度: ${pickupService}`);
  } else if (pickupService === "during_window") {
    if (input.pickupWindowStartTime) {
      await fillSchedulingTimeField(
        page,
        /Start Time/i,
        input.pickupWindowStartTime,
      );
    }
    if (input.pickupWindowEndTime) {
      await fillSchedulingTimeField(
        page,
        /End Time/i,
        input.pickupWindowEndTime,
      );
    }
  } else if (pickupService === "have_appointment" && input.pickupAppointmentTime) {
    await fillSchedulingTimeField(
      page,
      /^Time\*|^Time$/i,
      input.pickupAppointmentTime,
    );
  }

  const deliveryLabels =
    FLOCK_DELIVERY_SERVICE_RPA_LABELS[deliveryService] ??
    FLOCK_DELIVERY_SERVICE_RPA_LABELS.standard_fcfs;
  if (!(await selectSchedulingRadio(page, deliveryLabels!))) {
    console.warn(`[flock-form] 未选中派送调度: ${deliveryService}`);
  } else if (deliveryService === "during_window") {
    if (input.deliveryWindowStartTime) {
      await fillSchedulingTimeField(
        page,
        /Start Time/i,
        input.deliveryWindowStartTime,
      );
    }
    if (input.deliveryWindowEndTime) {
      await fillSchedulingTimeField(
        page,
        /End Time/i,
        input.deliveryWindowEndTime,
      );
    }
    if (input.deliveryWindowDate) {
      await fillSchedulingDateField(
        page,
        /^Date\*|^Date$/i,
        input.deliveryWindowDate,
      );
    }
  } else if (deliveryService === "have_appointment") {
    if (input.deliveryAppointmentTime) {
      await fillSchedulingTimeField(
        page,
        /^Time\*|^Time$/i,
        input.deliveryAppointmentTime,
      );
    }
    if (input.deliveryAppointmentDate) {
      await fillSchedulingDateField(
        page,
        /^Date\*|^Date$/i,
        input.deliveryAppointmentDate,
      );
    }
  } else if (deliveryService === "must_arrive_by") {
    if (input.deliveryMustArriveByDate) {
      await fillSchedulingDateField(
        page,
        /^Date\*|^Date$/i,
        input.deliveryMustArriveByDate,
      );
    }
    if (typeof input.callForDeliveryAppointment === "boolean") {
      const box = page
        .getByRole("checkbox", {
          name: /Call for delivery appointment/i,
        })
        .first();
      if ((await flockLocatorCount(box)) > 0) {
        const disabled = await box.isDisabled().catch(() => true);
        if (!disabled) {
          const on = await box.isChecked().catch(() => false);
          if (on !== input.callForDeliveryAppointment) {
            await box.click({ force: true }).catch(() => undefined);
          }
        }
      }
    }
  }
  await pause(page);
}

/** 附加服务 + 车型（对齐标准：Unloading + 默认三车型） */
async function applyLoggedInServicesAndVehicles(
  page: Page,
  input: LoggedInFormInput,
): Promise<void> {
  const unloadProbe = page
    .getByRole("button", { name: "Unloading Services" })
    .first();
  if (!(await unloadProbe.isVisible().catch(() => false))) {
    const section = page
      .getByRole("button", { name: /Additional Services/i })
      .first();
    if (await section.isVisible().catch(() => false)) {
      await section.click().catch(() => undefined);
      await page.waitForTimeout(400);
    }
  }

  const wantServices = new Set(
    (Array.isArray(input.additionalServices)
      ? input.additionalServices
      : ["unloading"]
    ).map((s) => s.trim()).filter(Boolean),
  );
  console.log(
    `[flock-form] 附加服务目标=[${[...wantServices].join(",")}]`,
  );
  for (const [id, label] of Object.entries(FLOCK_SERVICE_RPA_LABELS)) {
    await ensureChip(page, label, wantServices.has(id));
  }
  await pause(page);

  const wantVehicleIds = (
    input.vehicleTypes?.length
      ? input.vehicleTypes
      : [...FLOCK_DEFAULT_VEHICLE_IDS]
  ).map((s) => s.trim());

  /**
   * 官网默认已勾选 Box Truck / Dry Van / Refrigerated。
   * 误判选中态再点 = 把默认关掉，只剩冷藏车还会触发温控校验。
   * 目标即默认三选时：禁止点击车型芯片。
   */
  if (isDefaultVehicleSet(wantVehicleIds)) {
    console.log(
      "[flock-form] 车型为目标默认三选，跳过点击（保留官网默认，防误取消）",
    );
  } else {
    const wantVehicles = new Set(wantVehicleIds);
    console.log(
      `[flock-form] 车型自定义目标=[${[...wantVehicles].join(",")}]`,
    );
    for (const [id, label] of Object.entries(FLOCK_VEHICLE_RPA_LABELS)) {
      await ensureChip(page, label, wantVehicles.has(id));
    }
  }
  await pause(page);

  // 若只剩冷藏车且无温控：把默认厢式/干货加回来，消除阻断提交的红字
  const reefer = page
    .getByRole("button", { name: "Refrigerated Truck" })
    .first();
  const box = page.getByRole("button", { name: "Box Truck" }).first();
  const dry = page.getByRole("button", { name: "Dry Van" }).first();
  const temp = page.getByRole("button", { name: "Temperature Control" }).first();
  if (
    (await reefer.isVisible().catch(() => false)) &&
    (await isChipSelected(reefer)) &&
    !(await isChipSelected(temp).catch(() => false))
  ) {
    if (await box.isVisible().catch(() => false)) {
      if (!(await isChipSelected(box))) {
        await box.click({ force: true });
        console.log("[flock-form] 恢复 Box Truck（避免仅冷藏车阻断）");
      }
    }
    if (await dry.isVisible().catch(() => false)) {
      if (!(await isChipSelected(dry))) {
        await dry.click({ force: true });
        console.log("[flock-form] 恢复 Dry Van（避免仅冷藏车阻断）");
      }
    }
    await page.waitForTimeout(400);
  }

  await applyLoggedInScheduling(page, input);

  if (input.callBeforePickup === true) {
    // Quick/小批量：官网「提货前致电」为灰色，禁止强点
    const box = page
      .getByRole("checkbox", {
        name: /Carrier please call before pickup/i,
      })
      .first();
    if ((await flockLocatorCount(box)) > 0) {
      const disabled = await box.isDisabled().catch(() => true);
      if (!disabled) {
        await setCheckbox(page, /Carrier please call before pickup/i, true);
      } else {
        console.log(
          "[flock-form] 跳过提货前致电（总重 ≤5000 / checkbox disabled）",
        );
      }
    }
  } else if (input.callBeforePickup === false) {
    const box = page
      .getByRole("checkbox", {
        name: /Carrier please call before pickup/i,
      })
      .first();
    if ((await flockLocatorCount(box)) > 0) {
      const disabled = await box.isDisabled().catch(() => true);
      if (!disabled) {
        await setCheckbox(page, /Carrier please call before pickup/i, false);
      }
    }
  }
  if (input.callBeforeDelivery === true) {
    const box = page
      .getByRole("checkbox", {
        name: /Carrier please call before delivery/i,
      })
      .first();
    if ((await flockLocatorCount(box)) > 0) {
      const disabled = await box.isDisabled().catch(() => true);
      if (!disabled) {
        await setCheckbox(page, /Carrier please call before delivery/i, true);
      } else {
        console.log(
          "[flock-form] 跳过派送前致电（官网当前禁用 / checkbox disabled）",
        );
      }
    }
  } else if (input.callBeforeDelivery === false) {
    const box = page
      .getByRole("checkbox", {
        name: /Carrier please call before delivery/i,
      })
      .first();
    if ((await flockLocatorCount(box)) > 0) {
      const disabled = await box.isDisabled().catch(() => true);
      if (!disabled) {
        await setCheckbox(page, /Carrier please call before delivery/i, false);
      }
    }
  }
}

/** 填写登录后 Quick 查价表单 */
export async function fillFlockLoggedInQuoteForm(
  page: Page,
  input: LoggedInFormInput,
): Promise<{ ok: boolean; error?: string }> {
  try {
    return await fillFlockLoggedInQuoteFormInner(page, input);
  } catch (error) {
    if (isFlockPageClosedError(error)) {
      return { ok: false, error: flockPageClosedMessage("填写 Quick 表单") };
    }
    throw error;
  }
}

async function fillFlockLoggedInQuoteFormInner(
  page: Page,
  input: LoggedInFormInput,
): Promise<{ ok: boolean; error?: string }> {
  await ensureQuickMode(page);

  if (!(await fillLoggedInPickupDate(page, input.pickupDate))) {
    return {
      ok: false,
      error: "QUOTE_ENTRY_UNAVAILABLE：无法填写 Shipment Pickup 日期",
    };
  }
  await pause(page);

  if (
    !(await fillTextbox(
      page,
      [/Pickup ZIP Code/i, /Pickup ZIP/i],
      input.pickupZip,
    ))
  ) {
    return { ok: false, error: "QUOTE_ENTRY_UNAVAILABLE：无法定位取件 ZIP" };
  }
  await pause(page);

  const pickupTypes = [
    ...flockLocationRpaLabels(input.pickupLocationType ?? "business_with_dock"),
  ];
  if (
    !(await selectFlockComboboxOption(page, /Pickup Type/i, pickupTypes))
  ) {
    return { ok: false, error: "QUOTE_ENTRY_UNAVAILABLE：无法选择 Pickup Type" };
  }
  await pause(page);

  if (
    !(await fillTextbox(
      page,
      [/Delivery ZIP Code/i, /Delivery ZIP/i],
      input.deliveryZip,
    ))
  ) {
    return { ok: false, error: "QUOTE_ENTRY_UNAVAILABLE：无法定位派送 ZIP" };
  }
  await pause(page);

  const deliveryTypes = [
    ...flockLocationRpaLabels(
      input.deliveryLocationType ?? "business_with_dock",
    ),
  ];
  if (
    !(await selectFlockComboboxOption(page, /Delivery Type/i, deliveryTypes))
  ) {
    return {
      ok: false,
      error: "QUOTE_ENTRY_UNAVAILABLE：无法选择 Delivery Type",
    };
  }
  await pause(page);

  // 地点类型附属（Residential/Farm 等）：对齐官网勾选项
  await applyLoggedInLocationAccessorials(page, input);
  await pause(page);

  if (
    !(await fillTextbox(page, [/Quantity/i], String(input.palletCount)))
  ) {
    return { ok: false, error: "QUOTE_ENTRY_UNAVAILABLE：无法填写 Quantity" };
  }
  await pause(page);

  const packaging = [
    ...flockPackagingRpaLabels(input.packagingType ?? "pallets_48x40"),
  ];
  if (
    !(await selectFlockComboboxOption(page, /Packaging Type/i, packaging))
  ) {
    return {
      ok: false,
      error: "QUOTE_ENTRY_UNAVAILABLE：无法选择 Packaging Type",
    };
  }
  await pause(page);

  for (const [names, value, label] of [
    [[/Length \(in\)/i, /^Length/i], String(input.lengthIn), "长度"],
    [[/Width \(in\)/i, /^Width/i], String(input.widthIn), "宽度"],
    [[/Height \(in\)/i, /^Height/i], String(input.heightIn), "高度"],
  ] as const) {
    // Bags 等需长宽高；部分 Pallet 选项可能无独立 Length（录制中 Bags 有）
    const filled = await fillTextbox(page, [...names], value);
    if (!filled && label === "高度") {
      return {
        ok: false,
        error: `QUOTE_ENTRY_UNAVAILABLE：无法定位${label}`,
      };
    }
    if (filled) {
      await pause(page);
    }
  }

  if (
    !(await fillTextbox(
      page,
      [/Total Weight \(lbs\)/i, /Total Weight/i, /Total shipment weight/i],
      String(input.totalWeightLb),
    ))
  ) {
    return { ok: false, error: "QUOTE_ENTRY_UNAVAILABLE：无法填写 Total Weight" };
  }
  await pause(page);

  const freightLabels = [
    ...flockFreightClassRpaLabels(input.freightClass ?? "density"),
  ];
  if (
    !(await selectFlockComboboxOption(page, /Freight Class/i, freightLabels))
  ) {
    return {
      ok: false,
      error: "QUOTE_ENTRY_UNAVAILABLE：无法选择 Freight Class",
    };
  }
  await pause(page);

  const description = input.description?.trim() || DEFAULT_DESCRIPTION;
  if (
    !(await fillTextarea(
      page,
      [/Description of Contents/i, /Description/i],
      description,
    ))
  ) {
    return {
      ok: false,
      error: "QUOTE_ENTRY_UNAVAILABLE：无法填写 Description of Contents",
    };
  }
  await pause(page);

  // Options：只点一次，禁止 checkbox + 文案双击导致取消
  await ensureOptionToggle(page, "Stackable", Boolean(input.stackable));
  await ensureOptionToggle(page, "Turnable", Boolean(input.turnable));
  await pause(page);

  await applyLoggedInServicesAndVehicles(page, input);

  return { ok: true };
}

export async function clickFlockLoggedInQuoteSubmit(
  page: Page,
): Promise<boolean> {
  const byTestId = page.getByTestId("quote-request-quick-form__submit_button");
  if (
    (await flockLocatorCount(byTestId)) > 0 &&
    (await byTestId.first().isVisible().catch(() => false))
  ) {
    const btn = byTestId.first();
    // 车型/校验红字时按钮 disable，最多等 15s
    try {
      await btn.waitFor({ state: "visible", timeout: 5_000 });
      await page
        .waitForFunction(
          (el) => {
            const b = el as HTMLButtonElement;
            return !b.disabled && !b.classList.contains("Mui-disabled");
          },
          await btn.elementHandle(),
          { timeout: 15_000 },
        )
        .catch(() => undefined);
      await btn.click({ timeout: 5_000 });
      return true;
    } catch (err) {
      if (isFlockPageClosedError(err)) return false;
      console.warn(
        `[flock-form] 提交按钮不可用: ${
          err instanceof Error ? err.message.slice(0, 120) : err
        }`,
      );
      return false;
    }
  }
  const candidates = [
    page.getByRole("button", { name: /Generate my quote/i }),
    page.getByRole("button", { name: /Get (a )?quote|Submit|Request quote/i }),
  ];
  for (const loc of candidates) {
    if (
      (await flockLocatorCount(loc)) > 0 &&
      (await loc.first().isVisible().catch(() => false))
    ) {
      await loc.first().click();
      return true;
    }
  }
  return false;
}
