import type { Locator, Page } from "playwright";
import type { QuoteRequest } from "@/modules/providers/quote-provider";
import { captureRpaDebugScreenshot } from "@/workers/rpa/page-prep";
import { readWidgetCombinedText } from "@/workers/rpa/address-commit";
import {
  isAddressChipVisuallyCommitted,
  isPickupChipVisuallyReady,
} from "@/workers/rpa/address-chip-visual";
import {
  addressInputMatchesQuery,
  isAddressSuggestionDropdownOpen,
} from "@/workers/rpa/address-suggestions";
import { isRpaFastQuoteMode, isRpaBlindAddressFlow } from "@/lib/rpa/env";
import { expandDirectionalStreet } from "@/lib/address/street-normalize";
import { COLLECT_SUGGESTION_MOUSE_TARGETS } from "@/workers/rpa/kernel/browser-scripts";

type AddressFields = QuoteRequest["pickup"];

export type SuggestionMouseTarget = {
  x: number;
  y: number;
  width: number;
  height: number;
  text: string;
  top: number;
};

/** 收集输入框下方联想行的视口坐标（不依赖 role=listbox / PAC） */
export async function collectSuggestionMouseTargets(
  page: Page,
  input: Locator,
): Promise<SuggestionMouseTarget[]> {
  const handle = await input.elementHandle().catch(() => null);
  if (!handle) {
    return [];
  }
  try {
    const targets = (await page.evaluate(
      COLLECT_SUGGESTION_MOUSE_TARGETS,
      handle,
    )) as SuggestionMouseTarget[];
    return Array.isArray(targets) ? targets : [];
  } finally {
    await handle.dispose().catch(() => undefined);
  }
}

/** 读取 widget 可见文案，作为截图等价的视觉确认依据 */
export async function readWidgetVisualText(
  page: Page,
  widgetSelector: string,
): Promise<string> {
  return readWidgetCombinedText(page, widgetSelector).catch(() => "");
}

/**
 * 唯一联想确认：截图两行 chip（门牌街名 + City, ST）。
 * 输入框内多逗号长串打字态 → 未确认。
 */
export async function isAddressCommittedVisually(
  page: Page,
  widgetSelector: string,
  address: AddressFields,
  _input?: Locator,
): Promise<boolean> {
  return isAddressChipVisuallyCommitted(page, widgetSelector, address);
}

/** 人工录制同款：getByText(street+city首词粘连) 等多候选 probe */
export function buildRecordingStyleTextProbes(
  street: string,
  city?: string,
  mothershipDisplayLabel?: string,
): string[] {
  const probes: string[] = [];
  const cityFirst = city?.trim().split(/\s+/)[0] ?? "";

  const addProbe = (streetPart: string) => {
    const s = streetPart.trim();
    if (!s) {
      return;
    }
    if (cityFirst) {
      probes.push(`${s}${cityFirst}`);
      probes.push(`${s}${cityFirst},`);
      probes.push(`${s}, ${cityFirst}`);
    }
    probes.push(s);
  };

  if (mothershipDisplayLabel?.trim()) {
    const labelParts = mothershipDisplayLabel.split(",").map((p) => p.trim());
    addProbe(labelParts[0] ?? "");
    if (labelParts[1]) {
      const labelCityFirst = labelParts[1].split(/\s+/)[0] ?? "";
      if (labelParts[0] && labelCityFirst) {
        probes.push(`${labelParts[0]}${labelCityFirst}`);
        probes.push(`${labelParts[0]}${labelCityFirst},`);
        probes.push(`${labelParts[0]}, ${labelCityFirst}`);
      }
    }
  }

  addProbe(street.split(",")[0]?.trim() ?? street.trim());

  const expanded = expandDirectionalStreet(street);
  if (expanded) {
    addProbe(expanded);
  }

  return [...new Set(probes.filter((p) => p.length >= 6))];
}

export function buildRecordingStyleTextProbe(
  street: string,
  city?: string,
): string {
  return buildRecordingStyleTextProbes(street, city)[0] ?? street;
}

export async function clickSuggestionLikeRecording(
  page: Page,
  street: string,
  city?: string,
  mothershipDisplayLabel?: string,
): Promise<{ clicked: boolean; probe: string; box?: { width: number; height: number } | null }> {
  const probes = buildRecordingStyleTextProbes(street, city, mothershipDisplayLabel);

  for (const probe of probes) {
    const loc = page.getByText(probe, { exact: false }).first();
    if (!(await loc.isVisible().catch(() => false))) {
      continue;
    }
    const box = await loc.boundingBox().catch(() => null);
    if (box && (box.width > 900 || box.height > 200)) {
      continue;
    }
    if (box && box.width > 500) {
      continue;
    }
    if (box) {
      await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2, {
        delay: 40,
      });
    } else {
      await loc.click({ force: true, timeout: 2_000 }).catch(() => undefined);
    }
    return { clicked: true, probe, box };
  }

  return { clicked: false, probe: probes[0] ?? street };
}

/**
 * 盲执行：尽力点联想，不检测是否选中成功。
 * 顺序：recording getByText → ArrowDown+Enter → Escape+Tab
 */
export async function blindClickAddressSuggestion(
  page: Page,
  input: Locator,
  address: AddressFields,
  label = "blind-suggestion",
): Promise<void> {
  console.log(`[rpa] ${label}: blind-flow 点选（不检测确认）`);
  await input.click({ force: true, timeout: 3_000 }).catch(() => undefined);
  await page.waitForTimeout(80);
  await page.keyboard.press("ArrowDown").catch(() => undefined);
  await page.waitForTimeout(120);

  const recording = await clickSuggestionLikeRecording(
    page,
    address.street,
    address.city,
    address.mothershipDisplayLabel,
  );
  if (recording.clicked) {
    console.log(`[rpa] ${label}: recording probe="${recording.probe}"`);
  } else {
    await page.keyboard.press("Enter").catch(() => undefined);
    console.log(`[rpa] ${label}: recording 未命中，已 ArrowDown+Enter`);
  }
  await page.waitForTimeout(150);
  await page.keyboard.press("Escape").catch(() => undefined);
  await page.keyboard.press("Tab").catch(() => undefined);
  await page.waitForTimeout(100);
}

/**
 * 模拟鼠标点击联想行，仅以 widget 可见文案（截图等价）判定是否选中。
 * 点击成功日志不算数；必须看到地址已写入 widget 才返回 true。
 */
export async function mouseClickSuggestionUntilVisualConfirmed(
  page: Page,
  input: Locator,
  widgetSelector: string,
  address: AddressFields,
  label = "mouse-suggestion",
  options?: { reopenSuggestions?: boolean; blindFlow?: boolean },
): Promise<boolean> {
  if (options?.blindFlow || isRpaBlindAddressFlow()) {
    await blindClickAddressSuggestion(page, input, address, label);
    return true;
  }

  if (
    await isAddressCommittedVisually(page, widgetSelector, address, input)
  ) {
    console.log(`[rpa] ${label}: 视觉已确认（下拉已关且非纯输入态），跳过点击`);
    return true;
  }

  const fast = isRpaFastQuoteMode();
  const settleMs = fast ? 100 : 450;
  const focusMs = fast ? 80 : 300;

  await input.click({ force: true, timeout: 3_000 }).catch(() => undefined);
  await page.waitForTimeout(focusMs);

  if (options?.reopenSuggestions) {
    await input.click({ force: true, timeout: 2_000 }).catch(() => undefined);
    await input.press("End").catch(() => undefined);
    await input.press("Backspace").catch(() => undefined);
    await page.waitForTimeout(fast ? 80 : 200);
    await page.keyboard.press("ArrowDown").catch(() => undefined);
    await page.waitForTimeout(fast ? 150 : 300);
    if (!(await isAddressSuggestionDropdownOpen(page))) {
      await page.keyboard.press("ArrowDown").catch(() => undefined);
      await page.waitForTimeout(fast ? 100 : 200);
    }
  }

  const recordingClick = await clickSuggestionLikeRecording(
    page,
    address.street,
    address.city,
    address.mothershipDisplayLabel,
  );
  if (recordingClick.clicked) {
    await page.waitForTimeout(settleMs);
    if (!fast) {
      await captureRpaDebugScreenshot(page, `${label}-recording-click`);
    }
    const recordingOk = await isAddressCommittedVisually(
      page,
      widgetSelector,
      address,
      input,
    );
    console.log(
      `[rpa] ${label}: recording-click probe="${recordingClick.probe}" visual=${recordingOk}`,
    );
    if (recordingOk) {
      return true;
    }
  }

  let targets = await collectSuggestionMouseTargets(page, input);
  if (!targets.length) {
    await page.waitForTimeout(fast ? 150 : 400);
    targets = await collectSuggestionMouseTargets(page, input);
  }

  if (!targets.length) {
    if (!fast) {
      await captureRpaDebugScreenshot(page, `${label}-no-targets`);
    }
    console.log(`[rpa] ${label}: 未找到可点击的联想行`);
    return false;
  }

  console.log(
    `[rpa] ${label}: 找到 ${targets.length} 个候选，` +
      targets
        .slice(0, 3)
        .map((t) => `"${t.text.slice(0, 36)}"@${Math.round(t.x)},${Math.round(t.y)}`)
        .join("; "),
  );

  for (let i = 0; i < targets.length; i++) {
    const target = targets[i]!;
    await page.mouse.move(target.x, target.y);
    await page.mouse.click(target.x, target.y, { delay: 40 });
    await page.waitForTimeout(settleMs);

    if (!fast) {
      await captureRpaDebugScreenshot(page, `${label}-after-click-${i}`);
    }

    const widgetText = await readWidgetVisualText(page, widgetSelector);
    const confirmed = await isAddressCommittedVisually(
      page,
      widgetSelector,
      address,
      input,
    );
    const dropdownOpen = await isAddressSuggestionDropdownOpen(page);

    console.log(
      `[rpa] ${label}: click#${i} visual=${confirmed} dropdown=${dropdownOpen} ` +
        `widget="${widgetText.slice(0, 80)}"`,
    );

    if (confirmed) {
      return true;
    }

    if (!dropdownOpen) {
      await input.click({ force: true, timeout: 2_000 }).catch(() => undefined);
      await page.waitForTimeout(250);
      targets = await collectSuggestionMouseTargets(page, input);
      if (!targets.length) {
        break;
      }
    }
  }

  await captureRpaDebugScreenshot(page, `${label}-all-failed`);
  return false;
}
