import type { Page } from "playwright";

/** 候选出现后 / 点选前后：焦点、combobox、pac、listbox 快照（仅取证，不改交互） */
export type SelectionTraceSnapshot = {
  label: string;
  at: number;
  activeElement: {
    tagName: string;
    role: string | null;
    className: string;
    id: string;
    ariaExpanded: string | null;
    ariaAutocomplete: string | null;
    ariaActivedescendant: string | null;
    placeholder: string | null;
    valuePreview: string;
    isPacTarget: boolean;
  } | null;
  activeDescendant: {
    id: string;
    tagName: string;
    role: string | null;
    className: string;
    ariaSelected: string | null;
    textPreview: string;
  } | null;
  pac: {
    visible: boolean;
    itemCount: number;
    highlightedIndex: number;
    items: Array<{ index: number; className: string; textPreview: string }>;
  };
  listboxOptions: Array<{
    index: number;
    tagName: string;
    role: string | null;
    className: string;
    ariaSelected: string | null;
    textPreview: string;
  }>;
  widgetInputs: Array<{
    tagName: string;
    role: string | null;
    className: string;
    placeholder: string;
    ariaActivedescendant: string | null;
    isPacTarget: boolean;
    valuePreview: string;
  }>;
  comboboxAlive: boolean;
};

export type ManualInteractionRecord = {
  kind: "click" | "keydown";
  at: number;
  key?: string;
  target: {
    tagName: string;
    role: string | null;
    className: string;
    id: string;
    textPreview: string;
    closestOption: string | null;
    closestPacItem: string | null;
    dataOptionId: string | null;
    closestMothershipSuggestion: string | null;
  };
};

const CAPTURE_SELECTION_TRACE = `(function(label) {
  function summarize(el) {
    if (!el) return null;
    var html = el;
    return {
      tagName: html.tagName || "",
      role: html.getAttribute("role"),
      className: (html.className && String(html.className)) || "",
      id: html.id || "",
      ariaExpanded: html.getAttribute("aria-expanded"),
      ariaAutocomplete: html.getAttribute("aria-autocomplete"),
      ariaActivedescendant: html.getAttribute("aria-activedescendant"),
      placeholder: html.getAttribute("placeholder"),
      valuePreview: ("value" in html && html.value)
        ? String(html.value).replace(/\\s+/g, " ").trim().slice(0, 80)
        : (html.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 80),
      isPacTarget: html.classList && html.classList.contains("pac-target-input"),
    };
  }
  function resolveDescendant(id) {
    if (!id) return null;
    var el = document.getElementById(id);
    if (!el) return null;
    return {
      id: id,
      tagName: el.tagName || "",
      role: el.getAttribute("role"),
      className: (el.className && String(el.className)) || "",
      ariaSelected: el.getAttribute("aria-selected"),
      textPreview: (el.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 100),
    };
  }
  var active = document.activeElement;
  var activeSummary = summarize(active);
  var descendant = activeSummary && activeSummary.ariaActivedescendant
    ? resolveDescendant(activeSummary.ariaActivedescendant)
    : null;
  var pacContainer = document.querySelector(".pac-container");
  var pacVisible = !!(pacContainer && pacContainer.offsetParent !== null);
  var pacItems = pacContainer
    ? Array.prototype.slice.call(pacContainer.querySelectorAll(".pac-item"))
    : [];
  var highlightedIndex = -1;
  var pacItemSummaries = [];
  for (var i = 0; i < pacItems.length; i += 1) {
    var item = pacItems[i];
    var cls = (item.className && String(item.className)) || "";
    if (cls.indexOf("pac-item-selected") >= 0 || cls.indexOf("pac-item-hover") >= 0) {
      highlightedIndex = i;
    }
    pacItemSummaries.push({
      index: i,
      className: cls.slice(0, 120),
      textPreview: (item.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 100),
    });
  }
  var listboxOptions = [];
  var optionNodes = document.querySelectorAll('[role="listbox"] [role="option"]');
  for (var j = 0; j < optionNodes.length && j < 12; j += 1) {
    var opt = optionNodes[j];
    listboxOptions.push({
      index: j,
      tagName: opt.tagName || "",
      role: opt.getAttribute("role"),
      className: ((opt.className && String(opt.className)) || "").slice(0, 120),
      ariaSelected: opt.getAttribute("aria-selected"),
      textPreview: (opt.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 100),
    });
  }
  var widget = document.querySelector("#react-quoter-landing-plugin");
  var widgetInputs = [];
  if (widget) {
    var inputs = widget.querySelectorAll("input, textarea, [role='combobox']");
    for (var k = 0; k < inputs.length && k < 8; k += 1) {
      var inp = inputs[k];
      widgetInputs.push({
        tagName: inp.tagName || "",
        role: inp.getAttribute("role"),
        className: ((inp.className && String(inp.className)) || "").slice(0, 120),
        placeholder: inp.getAttribute("placeholder") || "",
        ariaActivedescendant: inp.getAttribute("aria-activedescendant"),
        isPacTarget: inp.classList && inp.classList.contains("pac-target-input"),
        valuePreview: ("value" in inp && inp.value)
          ? String(inp.value).replace(/\\s+/g, " ").trim().slice(0, 80)
          : "",
      });
    }
  }
  var comboboxAlive = widgetInputs.some(function(w) {
    return !!w.ariaActivedescendant;
  }) || highlightedIndex >= 0;
  return {
    label: label,
    at: Date.now(),
    activeElement: activeSummary,
    activeDescendant: descendant,
    pac: {
      visible: pacVisible,
      itemCount: pacItems.length,
      highlightedIndex: highlightedIndex,
      items: pacItemSummaries,
    },
    listboxOptions: listboxOptions,
    widgetInputs: widgetInputs,
    comboboxAlive: comboboxAlive,
  };
})`;

const INSTALL_MANUAL_LISTENERS = `(function() {
  if (window.__rpaManualSelectionTrace) {
    return { ok: true, reason: "already-installed" };
  }
  window.__rpaManualSelectionTrace = { clicks: [], keys: [] };
  function closestMothershipSuggestionRow(el) {
    if (!el || !el.closest) return null;
    var widget = document.querySelector("#react-quoter-landing-plugin");
    if (!widget || !widget.contains(el)) return null;
    var node = el;
    while (node && node !== widget) {
      var tag = node.tagName || "";
      if (tag !== "DIV" && tag !== "LI" && tag !== "BUTTON") {
        node = node.parentElement;
        continue;
      }
      var cls = (node.className && String(node.className)) || "";
      if (cls.indexOf("sc-") !== 0) {
        node = node.parentElement;
        continue;
      }
      var text = (node.textContent || "").replace(/\\s+/g, " ").trim();
      if (text.length < 18) {
        node = node.parentElement;
        continue;
      }
      if (/^(pick up from|deliver to|use my location)$/i.test(text)) {
        node = node.parentElement;
        continue;
      }
      if (node.querySelector && node.querySelector("input, textarea")) {
        node = node.parentElement;
        continue;
      }
      var clsShort = cls.split(/\\s+/).slice(0, 2).join(".");
      return tag + "." + clsShort + ":" + text.slice(0, 100);
    }
    return null;
  }
  function summarizeTarget(el) {
    if (!el || !el.closest) {
      return {
        tagName: "",
        role: null,
        className: "",
        id: "",
        textPreview: "",
        closestOption: null,
        closestPacItem: null,
        dataOptionId: null,
        closestMothershipSuggestion: null,
      };
    }
    var opt = el.closest('[role="option"], [data-option-id], button[data-option-id], li[role="option"]');
    var pac = el.closest(".pac-item");
    var dataOptionId = el.getAttribute("data-option-id");
    if (!dataOptionId && opt) {
      dataOptionId = opt.getAttribute("data-option-id");
    }
    var msRow = closestMothershipSuggestionRow(el);
    return {
      tagName: el.tagName || "",
      role: el.getAttribute("role"),
      className: ((el.className && String(el.className)) || "").slice(0, 160),
      id: el.id || "",
      textPreview: (el.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 120),
      closestOption: opt
        ? (opt.tagName + "#" + (opt.id || "") + "." + ((opt.className && String(opt.className)) || "").slice(0, 80))
        : null,
      closestPacItem: pac
        ? ("pac-item:" + ((pac.textContent || "").replace(/\\s+/g, " ").trim().slice(0, 80)))
        : null,
      dataOptionId: dataOptionId,
      closestMothershipSuggestion: msRow,
    };
  }
  document.addEventListener("click", function(e) {
    var t = e.target;
    window.__rpaManualSelectionTrace.clicks.push({
      kind: "click",
      at: Date.now(),
      target: summarizeTarget(t),
    });
  }, true);
  document.addEventListener("keydown", function(e) {
    window.__rpaManualSelectionTrace.keys.push({
      kind: "keydown",
      at: Date.now(),
      key: e.key,
      target: summarizeTarget(e.target),
    });
  }, true);
  return { ok: true, reason: "installed" };
})()`;

const DRAIN_MANUAL_INTERACTIONS = `(function() {
  var buf = window.__rpaManualSelectionTrace || { clicks: [], keys: [] };
  window.__rpaManualSelectionTrace = { clicks: [], keys: [] };
  return {
    clicks: buf.clicks || [],
    keys: buf.keys || [],
  };
})()`;

const traceBuffer: SelectionTraceSnapshot[] = [];

export function drainSelectionTraces(): SelectionTraceSnapshot[] {
  const out = [...traceBuffer];
  traceBuffer.length = 0;
  return out;
}

export function peekSelectionTraces(): SelectionTraceSnapshot[] {
  return [...traceBuffer];
}

export function formatSelectionTraceEvent(snapshot: SelectionTraceSnapshot): string {
  const active = snapshot.activeElement;
  const descendant = snapshot.activeDescendant?.id ?? "null";
  const pacHi =
    snapshot.pac.highlightedIndex >= 0
      ? `pac-highlight=${snapshot.pac.highlightedIndex}`
      : "pac-highlight=none";
  const listboxSel = snapshot.listboxOptions.find(
    (o) => o.ariaSelected === "true",
  );
  const listboxPart = listboxSel
    ? `listbox-selected=${listboxSel.index}`
    : "listbox-selected=none";
  const combobox = snapshot.comboboxAlive ? "combobox-alive" : "combobox-dead";
  const focus = active
    ? `focus=${active.tagName}${active.isPacTarget ? "+pac" : ""}`
    : "focus=null";
  return `selection-trace:${snapshot.label}:${focus}:aria-activedescendant=${descendant}:${pacHi}:${listboxPart}:${combobox}`;
}

function emptySelectionTraceSnapshot(label: string): SelectionTraceSnapshot {
  return {
    label,
    at: Date.now(),
    activeElement: null,
    activeDescendant: null,
    pac: { visible: false, itemCount: 0, highlightedIndex: -1, items: [] },
    listboxOptions: [],
    widgetInputs: [],
    comboboxAlive: false,
  };
}

export async function captureSelectionTrace(
  page: Page,
  label: string,
): Promise<SelectionTraceSnapshot> {
  let snapshot: SelectionTraceSnapshot;
  try {
    snapshot = (await page.evaluate(
      `${CAPTURE_SELECTION_TRACE}(${JSON.stringify(label)})`,
    )) as SelectionTraceSnapshot;
  } catch (error) {
    console.warn(
      `[rpa] selection-trace:capture-failed label=${label}`,
      error instanceof Error ? error.message : error,
    );
    snapshot = emptySelectionTraceSnapshot(label);
  }
  if (!snapshot || typeof snapshot !== "object" || !snapshot.label) {
    console.warn(`[rpa] selection-trace:capture-empty label=${label}`);
    snapshot = emptySelectionTraceSnapshot(label);
  }
  traceBuffer.push(snapshot);
  return snapshot;
}

export function logSelectionTrace(
  side: "pickup" | "delivery" | "manual" | "rpa",
  snapshot: SelectionTraceSnapshot | null | undefined,
): void {
  if (!snapshot) {
    console.log(`[rpa] selection-trace:${side} {"error":"snapshot为空"}`);
    return;
  }
  console.log(
    `[rpa] selection-trace:${side} ${JSON.stringify({
      label: snapshot.label,
      at: snapshot.at,
      activeElement: snapshot.activeElement,
      activeDescendant: snapshot.activeDescendant,
      pac: {
        visible: snapshot.pac.visible,
        itemCount: snapshot.pac.itemCount,
        highlightedIndex: snapshot.pac.highlightedIndex,
      },
      listboxCount: snapshot.listboxOptions.length,
      listboxSelected: snapshot.listboxOptions
        .filter((o) => o.ariaSelected === "true")
        .map((o) => o.index),
      comboboxAlive: snapshot.comboboxAlive,
      widgetInputs: snapshot.widgetInputs,
    })}`,
  );
}

export type ManualInteractionBundle = {
  clicks: ManualInteractionRecord[];
  keys: ManualInteractionRecord[];
};

const WIDGET_CHROME_LABEL_RE =
  /^(pick up from|deliver to|use my location)$/i;

/** MotherShip 联想行：styled-components DIV，非 role=option / pac-item */
export function isMothershipSuggestionClickTarget(
  target: ManualInteractionRecord["target"],
): boolean {
  if (
    target.closestOption ||
    target.closestPacItem ||
    target.dataOptionId ||
    target.closestMothershipSuggestion
  ) {
    return true;
  }
  const cls = target.className || "";
  if (!/\bsc-/.test(cls)) {
    return false;
  }
  const tag = (target.tagName || "").toUpperCase();
  if (tag === "INPUT" || tag === "BUTTON" || tag === "SVG") {
    return false;
  }
  const text = (target.textPreview || "").trim();
  if (text.length < 18 || WIDGET_CHROME_LABEL_RE.test(text)) {
    return false;
  }
  return /,|\bUSA\b|\bFL\b|\bCA\b|Street|Boulevard|Avenue|Hollywood|Key West/i.test(
    text,
  );
}

export function pickSelectionGoldInteractions(
  interactions: ManualInteractionBundle,
): {
  selectionClicks: ManualInteractionRecord[];
  selectionKeys: ManualInteractionRecord[];
} {
  const selectionClicks = interactions.clicks.filter((c) =>
    isMothershipSuggestionClickTarget(c.target),
  );
  const selectionKeys = interactions.keys.filter((k) => {
    const key = k.key ?? "";
    if (!["Enter", "ArrowDown", "ArrowUp", "Tab"].includes(key)) {
      return false;
    }
    const tag = (k.target.tagName || "").toUpperCase();
    return tag === "INPUT" || tag === "TEXTAREA";
  });
  return { selectionClicks, selectionKeys };
}

export function logManualInteractionGoldSample(
  phase: "pickup" | "delivery",
  interactions: ManualInteractionBundle,
): void {
  const { selectionClicks, selectionKeys } =
    pickSelectionGoldInteractions(interactions);
  console.log(
    `[manual] interactions-gold:${phase} clicks=${interactions.clicks.length} keys=${interactions.keys.length} selectionClicks=${selectionClicks.length} selectionKeys=${selectionKeys.length}`,
  );
  if (selectionClicks.length > 0) {
    const last = selectionClicks[selectionClicks.length - 1]!;
    console.log(
      `[manual] interactions-gold:${phase} last-selection-click ${JSON.stringify(last.target)}`,
    );
  } else if (selectionKeys.length > 0) {
    const last = selectionKeys[selectionKeys.length - 1]!;
    console.log(
      `[manual] interactions-gold:${phase} last-selection-key ${JSON.stringify({ key: last.key, target: last.target })}`,
    );
  } else {
    console.warn(
      `[manual] ⚠ interactions-gold:${phase} 未捕获到联想点选。请用鼠标点联想行（sc- DIV）或键盘 ↓+Enter 后再按检查点。`,
    );
  }
}

export async function installManualSelectionListeners(
  page: Page,
): Promise<void> {
  const result = await page.evaluate(INSTALL_MANUAL_LISTENERS);
  console.log(`[rpa] selection-trace:manual-listeners ${JSON.stringify(result)}`);
}

export async function drainManualInteractions(page: Page): Promise<{
  clicks: ManualInteractionRecord[];
  keys: ManualInteractionRecord[];
}> {
  try {
    return (await page.evaluate(DRAIN_MANUAL_INTERACTIONS)) as {
      clicks: ManualInteractionRecord[];
      keys: ManualInteractionRecord[];
    };
  } catch {
    return { clicks: [], keys: [] };
  }
}

export async function recordManualCheckpoint(
  page: Page,
  phase: string,
): Promise<{
  snapshot: SelectionTraceSnapshot;
  interactions: { clicks: ManualInteractionRecord[]; keys: ManualInteractionRecord[] };
}> {
  const interactions = await drainManualInteractions(page);
  const snapshot = await captureSelectionTrace(page, phase);
  logSelectionTrace("manual", snapshot);
  return { snapshot, interactions };
}
