(() => {
  if (window.__MMW_AGENT_BROWSER_CONTROL__) return;
  window.__MMW_AGENT_BROWSER_CONTROL__ = true;

  const STORAGE_KEY = "mmwAgentBrowserControlEnabled";
  const REQUEST_TYPE = "MMW_AGENT_BROWSER_CONTROL";
  const RESULT_TYPE = "MMW_AGENT_BROWSER_CONTROL_RESULT";
  const PING_TYPE = "MMW_AGENT_BROWSER_CONTROL_PING";
  const PONG_TYPE = "MMW_AGENT_BROWSER_CONTROL_PONG";
  const MAX_ELEMENTS = 160;
  const POINTER_STEP_MS = 120;
  const CONNECTED_IDLE_MS = 20000;
  const FRAME_Z_INDEX = 2147483645;
  const INTERACTIVE_SELECTOR = [
    "button",
    "a[href]",
    "input",
    "textarea",
    "select",
    "[contenteditable='true']",
    "[role='button']",
    "[role='link']",
    "[role='textbox']",
    "[role='combobox']",
    "[role='menuitem']",
    "[tabindex]:not([tabindex='-1'])",
    "[onclick]"
  ].join(",");
  const CONTENT_ACTIONS = new Set(["state", "snapshot", "click", "type", "scroll", "key", "move", "highlight", "wait"]);
  const BACKGROUND_ACTIONS = new Set([
    "navigate",
    "back",
    "forward",
    "reload",
    "screenshot",
    "new_tab",
    "open_tab",
    "list_tabs",
    "activate_tab",
    "close_tab"
  ]);

  let enabled = false;
  let connected = false;
  let overlayHost = null;
  let overlayShadow = null;
  let pointerNode = null;
  let pointerPosition = { x: Math.round(window.innerWidth / 2), y: Math.round(window.innerHeight / 2) };
  let pointerActiveTimer = 0;
  let connectedTimer = 0;
  let lastAgentSeenAt = 0;
  let lastAgentAction = "";
  let elementRefs = new Map();
  let elementRefSeed = 0;

  init();

  async function init() {
    enabled = await readEnabled();
    syncOverlay();
    chrome.storage?.onChanged?.addListener((changes, areaName) => {
      if (areaName !== "local" || !changes[STORAGE_KEY]) return;
      enabled = changes[STORAGE_KEY].newValue === true;
      syncOverlay();
    });
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
      if (!message || typeof message.type !== "string") return false;
      if (message.type === "MMW_AGENT_CONTROL_SET_ENABLED") {
        setEnabled(message.enabled === true)
          .then((result) => sendResponse({ ok: true, result }))
          .catch((error) => sendResponse({ ok: false, error: error.message || String(error) }));
        return true;
      }
      if (message.type === "MMW_AGENT_CONTROL_GET_STATE") {
        sendResponse({ ok: true, result: statePayload() });
        return true;
      }
      if (message.type === "MMW_AGENT_CONTROL_RESOLVE_TARGET") {
        try {
          sendResponse({ ok: true, result: resolveTargetPayload(message.payload || {}) });
        } catch (error) {
          sendResponse({ ok: false, error: error.message || String(error) });
        }
        return true;
      }
      if (message.type === "MMW_AGENT_CONTROL_TOUCH_CONNECTION") {
        touchConnection(message.action || "bridge");
        sendResponse({ ok: true, result: statePayload() });
        return true;
      }
      if (message.type === "MMW_AGENT_CONTROL_ACTION") {
        runAction(message.action, message.payload || {})
          .then((result) => sendResponse({ ok: true, result }))
          .catch((error) => sendResponse({ ok: false, error: error.message || String(error) }));
        return true;
      }
      return false;
    });
    window.addEventListener("message", handleWindowMessage);
    window.addEventListener("keydown", handleEscapeDisable, true);
  }

  async function readEnabled() {
    try {
      const values = await chrome.storage.local.get([STORAGE_KEY]);
      return values[STORAGE_KEY] === true;
    } catch {
      return false;
    }
  }

  async function setEnabled(nextEnabled) {
    enabled = nextEnabled === true;
    await chrome.storage.local.set({ [STORAGE_KEY]: enabled });
    if (!enabled) clearConnectionState();
    syncOverlay();
    return statePayload();
  }

  function syncOverlay() {
    const overlayVisible = enabled && connected;
    document.documentElement.classList.toggle("mmw-agent-control-active", overlayVisible);
    if (!overlayVisible) {
      overlayHost?.remove();
      overlayHost = null;
      overlayShadow = null;
      pointerNode = null;
      if (pointerActiveTimer) window.clearTimeout(pointerActiveTimer);
      pointerActiveTimer = 0;
      document.documentElement.classList.remove("mmw-agent-control-active");
      return;
    }
    ensureOverlay();
    updatePointer(pointerPosition.x, pointerPosition.y, false);
  }

  function touchConnection(action = "") {
    if (!enabled) return;
    connected = true;
    lastAgentSeenAt = Date.now();
    if (action) lastAgentAction = String(action);
    if (connectedTimer) window.clearTimeout(connectedTimer);
    connectedTimer = window.setTimeout(() => {
      connected = false;
      connectedTimer = 0;
      syncOverlay();
    }, CONNECTED_IDLE_MS);
    syncOverlay();
  }

  function clearConnectionState() {
    connected = false;
    lastAgentSeenAt = 0;
    lastAgentAction = "";
    if (connectedTimer) window.clearTimeout(connectedTimer);
    connectedTimer = 0;
  }

  function ensureOverlay() {
    if (overlayHost && overlayShadow) return;
    overlayHost = document.createElement("div");
    overlayHost.id = "mmw-agent-control-overlay";
    overlayHost.style.cssText = [
      "position:fixed",
      "inset:0",
      `z-index:${FRAME_Z_INDEX}`,
      "pointer-events:none"
    ].join(";");
    overlayShadow = overlayHost.attachShadow({ mode: "open" });
    overlayShadow.innerHTML = `
      <style>
        :host{all:initial}
        .frame{position:fixed;inset:0;pointer-events:none;font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
        .frame::before{
          content:"";
          position:fixed;
          inset:0;
          pointer-events:none;
          box-shadow:
            inset 0 0 18px rgba(38,132,255,.62),
            inset 0 0 46px rgba(38,132,255,.34),
            inset 0 0 92px rgba(38,132,255,.2),
            0 0 26px rgba(38,132,255,.42),
            0 0 68px rgba(38,132,255,.24);
        }
        .frame::after{
          content:"";
          position:fixed;
          inset:10px;
          border-radius:18px;
          pointer-events:none;
          box-shadow:
            inset 0 0 0 1px rgba(147,197,253,.38),
            0 0 22px rgba(59,130,246,.24);
          opacity:.82;
        }
        .badge{position:fixed;top:10px;left:50%;transform:translateX(-50%);height:30px;padding:0 12px;border-radius:999px;background:rgba(20,44,84,.92);border:1px solid rgba(96,165,250,.66);box-shadow:0 10px 28px rgba(15,23,42,.22),0 0 28px rgba(59,130,246,.24);color:#eff6ff;font:700 12px/30px system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;letter-spacing:0}
        .cursor{position:fixed;left:0;top:0;width:28px;height:28px;opacity:.46;transform:translate3d(0,0,0);filter:drop-shadow(0 4px 10px rgba(15,23,42,.28)) drop-shadow(0 0 10px rgba(29,124,255,.34));transition:transform .12s ease,opacity .18s ease,filter .18s ease;will-change:transform}
        .cursor.active{opacity:1;filter:drop-shadow(0 4px 10px rgba(15,23,42,.28)) drop-shadow(0 0 18px rgba(29,124,255,.62))}
        .cursor svg{display:block;width:28px;height:28px}
        .rings{position:fixed;left:0;top:0;width:32px;height:32px;border:2px solid rgba(29,124,255,.72);border-radius:999px;opacity:0;transform:translate(-50%,-50%) scale(.4);animation:none}
        .rings.pulse{animation:pulse .42s ease-out}
        .highlight{position:fixed;border:2px solid #1d7cff;background:rgba(29,124,255,.1);border-radius:6px;box-shadow:0 0 0 2px rgba(255,255,255,.76),0 8px 26px rgba(29,124,255,.22);pointer-events:none}
        @keyframes pulse{0%{opacity:.92;transform:translate(-50%,-50%) scale(.4)}100%{opacity:0;transform:translate(-50%,-50%) scale(1.8)}}
      </style>
      <div class="frame" aria-hidden="true">
        <span class="badge">\u0041\u0049 \u63a5\u7ba1\u4e2d</span>
        <span class="rings"></span>
        <span class="cursor">
          <svg viewBox="0 0 32 32" aria-hidden="true">
            <path d="M5 3.8 25.7 17 16.6 19.2 12.2 27.5 5 3.8Z" fill="#1d7cff" stroke="#fff" stroke-width="2" stroke-linejoin="round"/>
            <path d="M15.9 18.8 20.2 27.3" stroke="#0b45a8" stroke-width="2.2" stroke-linecap="round"/>
          </svg>
        </span>
      </div>
    `;
    pointerNode = overlayShadow.querySelector(".cursor");
    document.documentElement.append(overlayHost);
  }

  function updatePointer(x, y, active = true) {
    pointerPosition = {
      x: clamp(Number(x) || 0, 0, Math.max(0, window.innerWidth)),
      y: clamp(Number(y) || 0, 0, Math.max(0, window.innerHeight))
    };
    if (!pointerNode) return;
    pointerNode.style.transform = `translate3d(${Math.round(pointerPosition.x)}px, ${Math.round(pointerPosition.y)}px, 0)`;
    if (!active) return;
    pointerNode.classList.add("active");
    if (pointerActiveTimer) window.clearTimeout(pointerActiveTimer);
    pointerActiveTimer = window.setTimeout(() => {
      pointerNode?.classList.remove("active");
      pointerActiveTimer = 0;
    }, 1200);
  }

  function pulsePointer(x = pointerPosition.x, y = pointerPosition.y) {
    if (!overlayShadow) return;
    const ring = overlayShadow.querySelector(".rings");
    if (!ring) return;
    ring.style.left = `${Math.round(x)}px`;
    ring.style.top = `${Math.round(y)}px`;
    ring.classList.remove("pulse");
    void ring.offsetWidth;
    ring.classList.add("pulse");
  }

  function handleEscapeDisable(event) {
    if (!enabled || event.key !== "Escape" || !event.altKey) return;
    setEnabled(false).catch(() => {});
  }

  function handleWindowMessage(event) {
    const message = event.data;
    if (!isObject(message) || message.source === "mmw-plugin") return;
    if (message.type === PING_TYPE) {
      touchConnection("ping");
      postWindowResult(PONG_TYPE, message.requestId, true, statePayload(), "");
      return;
    }
    if (message.type !== REQUEST_TYPE) return;
    const requestId = String(message.requestId || `mmw-${Date.now()}-${Math.random().toString(36).slice(2)}`);
    const action = normalizeAction(message.action || message.command || message.name);
    if (!action) {
      postWindowResult(RESULT_TYPE, requestId, false, null, "action is required");
      return;
    }
    touchConnection(action);
    runAction(action, isObject(message.payload) ? message.payload : {})
      .then((result) => postWindowResult(RESULT_TYPE, requestId, true, result, ""))
      .catch((error) => postWindowResult(RESULT_TYPE, requestId, false, null, error.message || String(error)));
  }

  function postWindowResult(type, requestId, ok, result, error) {
    window.postMessage({
      source: "mmw-plugin",
      type,
      requestId,
      ok,
      result,
      error
    }, "*");
  }

  async function runAction(rawAction, payload) {
    const action = normalizeAction(rawAction);
    if (!action) throw new Error("action is required");
    if (action !== "state" && !enabled) throw new Error("AI接管未开启");
    if (CONTENT_ACTIONS.has(action)) return runContentAction(action, payload);
    if (BACKGROUND_ACTIONS.has(action)) return runBackgroundAction(action, payload);
    throw new Error(`不支持的浏览器动作：${action}`);
  }

  async function runContentAction(action, payload) {
    switch (action) {
      case "state":
        return statePayload();
      case "snapshot":
        return collectSnapshot(payload);
      case "click":
        return clickTarget(payload);
      case "type":
        return typeIntoTarget(payload);
      case "scroll":
        return scrollTarget(payload);
      case "key":
        return pressKey(payload);
      case "move":
        return movePointerAction(payload);
      case "highlight":
        return highlightTarget(payload);
      case "wait": {
        const waitedMs = clamp(Number(payload?.ms) || 300, 0, 30000);
        await delay(waitedMs);
        return { waitedMs };
      }
      default:
        throw new Error(`不支持的页面动作：${action}`);
    }
  }

  async function runBackgroundAction(action, payload) {
    const response = await chrome.runtime.sendMessage({
      type: "MMW_AGENT_CONTROL_BACKGROUND_ACTION",
      action,
      payload: isObject(payload) ? payload : {}
    });
    if (!response?.ok) throw new Error(response?.error || "后台浏览器动作失败");
    return response.result || {};
  }

  function statePayload() {
    return {
      enabled,
      connected,
      overlayVisible: enabled && connected,
      protocol: REQUEST_TYPE,
      resultType: RESULT_TYPE,
      version: chrome.runtime?.getManifest?.().version || "",
      url: location.href,
      title: document.title,
      visibilityState: document.visibilityState,
      viewport: {
        width: window.innerWidth,
        height: window.innerHeight,
        devicePixelRatio: window.devicePixelRatio || 1
      },
      scroll: {
        x: window.scrollX,
        y: window.scrollY,
        maxX: Math.max(0, document.documentElement.scrollWidth - window.innerWidth),
        maxY: Math.max(0, document.documentElement.scrollHeight - window.innerHeight)
      },
      pointer: { ...pointerPosition },
      lastAgentSeenAt,
      lastAgentAction
    };
  }

  function collectSnapshot(payload) {
    const limit = clamp(Number(payload?.limit) || 80, 1, MAX_ELEMENTS);
    const includeText = payload?.includeText !== false;
    elementRefs = new Map();
    elementRefSeed = 0;
    const elements = [];
    const seen = new Set();
    walkInteractiveRoots(
      document,
      createContext(null, 0, 0),
      (element, context) => {
        if (!(element instanceof HTMLElement)) return false;
        if (!isVisibleInContext(element, context)) return false;
        const info = buildTargetInfo(element, context);
        if (!info?.rect) return false;
        const ref = `e${++elementRefSeed}`;
        elementRefs.set(ref, info);
        elements.push({
          ref,
          tag: info.tag,
          role: info.role,
          type: info.type,
          text: includeText ? info.text : "",
          selector: info.selector,
          disabled: info.disabled,
          rect: info.rect,
          center: info.point,
          frameChain: info.frameChain
        });
        return elements.length >= limit;
      },
      seen
    );
    return {
      ...statePayload(),
      activeElement: describeElement(document.activeElement),
      elements
    };
  }

  async function clickTarget(payload) {
    const target = resolveTarget(payload);
    updatePointer(target.point.x, target.point.y);
    await delay(POINTER_STEP_MS);
    pulsePointer(target.point.x, target.point.y);
    const element = target.element || deepElementFromPoint(document, target.point.x, target.point.y)?.element;
    if (!(element instanceof HTMLElement)) throw new Error("未找到点击目标");
    dispatchMouseSequence(element, target.localPoint.x, target.localPoint.y);
    if (typeof element.click === "function") element.click();
    return { clicked: true, point: target.point, target: describeElement(element) };
  }

  async function typeIntoTarget(payload) {
    const target = resolveTarget(payload);
    const element = target.element;
    if (!(element instanceof HTMLElement)) throw new Error("未找到输入目标");
    element.scrollIntoView?.({ block: "center", inline: "center", behavior: "auto" });
    const fresh = refreshTargetInfo(target, target.point);
    updatePointer(fresh.point.x, fresh.point.y);
    await delay(POINTER_STEP_MS);
    element.focus?.({ preventScroll: true });
    const text = String(payload?.text ?? payload?.value ?? "");
    const clear = payload?.clear !== false;
    if (isEditableElement(element)) {
      setEditableValue(element, clear ? text : `${element.value || ""}${text}`);
    } else if (element.isContentEditable) {
      element.textContent = clear ? text : `${element.textContent || ""}${text}`;
      element.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertText", data: text }));
      element.dispatchEvent(new Event("change", { bubbles: true }));
    } else {
      throw new Error("目标不是可输入元素");
    }
    return { typed: true, length: text.length, target: describeElement(element) };
  }

  function scrollTarget(payload) {
    const targetElement = payload?.selector || payload?.ref || payload?.text ? resolveTarget(payload).element : null;
    const deltaX = Number(payload?.deltaX ?? payload?.x ?? 0) || 0;
    const deltaY = Number(payload?.deltaY ?? payload?.y ?? 0) || 0;
    const behavior = payload?.smooth ? "smooth" : "auto";
    if (targetElement) {
      if (payload?.to) {
        targetElement.scrollTo({ left: Number(payload.to.x || 0), top: Number(payload.to.y || 0), behavior });
      } else {
        targetElement.scrollBy({ left: deltaX, top: deltaY, behavior });
      }
      return { scrolled: true, target: describeElement(targetElement), scrollLeft: targetElement.scrollLeft, scrollTop: targetElement.scrollTop };
    }
    if (payload?.to) {
      window.scrollTo({ left: Number(payload.to.x || 0), top: Number(payload.to.y || 0), behavior });
    } else {
      window.scrollBy({ left: deltaX, top: deltaY, behavior });
    }
    return { scrolled: true, scroll: statePayload().scroll };
  }

  function pressKey(payload) {
    const key = String(payload?.key || payload?.text || "").trim();
    if (!key) throw new Error("key is required");
    if (key === "Tab") {
      focusNext(payload?.shift === true ? -1 : 1);
      return { key, focused: describeElement(document.activeElement) };
    }
    const target = payload?.selector || payload?.ref || payload?.text ? resolveTarget(payload).element : document.activeElement || document.body;
    const eventOptions = {
      key,
      code: String(payload?.code || key),
      bubbles: true,
      cancelable: true,
      ctrlKey: payload?.ctrlKey === true,
      altKey: payload?.altKey === true,
      shiftKey: payload?.shiftKey === true,
      metaKey: payload?.metaKey === true
    };
    target.dispatchEvent(new KeyboardEvent("keydown", eventOptions));
    target.dispatchEvent(new KeyboardEvent("keyup", eventOptions));
    if (key === "Enter" && target instanceof HTMLElement && typeof target.click === "function" && isButtonLike(target)) {
      target.click();
    }
    return { key, target: describeElement(target) };
  }

  async function movePointerAction(payload) {
    const point = resolvePoint(payload);
    updatePointer(point.x, point.y);
    await delay(POINTER_STEP_MS);
    return { moved: true, point };
  }

  function highlightTarget(payload) {
    const target = resolveTarget(payload);
    const rect = target.rect || { x: target.point.x - 16, y: target.point.y - 16, width: 32, height: 32 };
    if (!rect || !overlayShadow) return { highlighted: false };
    const node = document.createElement("span");
    node.className = "highlight";
    node.style.left = `${Math.round(rect.x)}px`;
    node.style.top = `${Math.round(rect.y)}px`;
    node.style.width = `${Math.round(rect.width)}px`;
    node.style.height = `${Math.round(rect.height)}px`;
    overlayShadow.querySelector(".frame")?.append(node);
    setTimeout(() => node.remove(), clamp(Number(payload?.ms) || 1200, 100, 8000));
    return { highlighted: true, rect };
  }

  function resolveTarget(payload) {
    if (!isObject(payload)) payload = {};
    const point = payload.x !== undefined || payload.y !== undefined ? resolvePoint(payload) : null;
    let info = null;
    if (payload.ref) info = elementRefs.get(String(payload.ref)) || null;
    if (!info && payload.selector) info = findBySelectorDeep(String(payload.selector));
    if (!info && payload.text) info = findByTextDeep(String(payload.text));
    if (!info && point) info = deepElementFromPoint(document, point.x, point.y);
    if (!info && document.activeElement instanceof HTMLElement) {
      info = buildTargetInfo(document.activeElement, createContext(null, 0, 0), point);
    }
    if (info?.element instanceof HTMLElement) {
      info.element.scrollIntoView?.({ block: "center", inline: "center", behavior: "auto" });
      return refreshTargetInfo(info, point);
    }
    if (point) {
      return {
        element: null,
        point,
        localPoint: point,
        rect: { x: point.x - 1, y: point.y - 1, width: 2, height: 2 },
        context: createContext(null, 0, 0),
        frameChain: []
      };
    }
    throw new Error("未找到目标元素");
  }

  function refreshTargetInfo(info, preferredPoint = null) {
    return buildTargetInfo(info.element, info.context, preferredPoint || info.point);
  }

  function resolveTargetPayload(payload) {
    const target = resolveTarget(payload);
    const element = target.element instanceof HTMLElement ? target.element : null;
    return {
      point: target.point,
      localPoint: target.localPoint,
      rect: target.rect,
      frameChain: Array.isArray(target.frameChain) ? target.frameChain.slice() : [],
      target: element ? describeElement(element) : null,
      editable: Boolean(element && (isEditableElement(element) || element.isContentEditable)),
      disabled: Boolean(element && isDisabled(element))
    };
  }

  function resolvePoint(payload) {
    return {
      x: clamp(Number(payload?.x) || 0, 0, Math.max(0, window.innerWidth)),
      y: clamp(Number(payload?.y) || 0, 0, Math.max(0, window.innerHeight))
    };
  }

  function walkInteractiveRoots(root, context, visit, seen = new Set()) {
    const directCandidates = queryAll(root, INTERACTIVE_SELECTOR);
    for (const element of directCandidates) {
      if (!(element instanceof HTMLElement) || seen.has(element)) continue;
      seen.add(element);
      if (visit(element, context) === true) return true;
    }
    const descendants = queryAll(root, "*");
    for (const node of descendants) {
      if (!(node instanceof HTMLElement)) continue;
      if (node.shadowRoot) {
        if (walkInteractiveRoots(node.shadowRoot, context, visit, seen) === true) return true;
      }
      if (node.tagName === "IFRAME") {
        const frameContext = getFrameContext(node, context);
        if (frameContext && walkInteractiveRoots(frameContext.root, frameContext.context, visit, seen) === true) {
          return true;
        }
      }
    }
    return false;
  }

  function findBySelectorDeep(selector) {
    let found = null;
    walkInteractiveRoots(
      document,
      createContext(null, 0, 0),
      (_element, _context) => false,
      new Set()
    );
    walkRoots(
      document,
      createContext(null, 0, 0),
      (root, context) => {
        const element = safeQuery(root, selector);
        if (!(element instanceof HTMLElement)) return false;
        if (!isVisibleInContext(element, context)) return false;
        found = buildTargetInfo(element, context);
        return true;
      }
    );
    return found;
  }

  function findByTextDeep(text) {
    const needle = compactText(text, 120).toLowerCase();
    if (!needle) return null;
    let found = null;
    walkInteractiveRoots(
      document,
      createContext(null, 0, 0),
      (element, context) => {
        if (!elementText(element).toLowerCase().includes(needle)) return false;
        found = buildTargetInfo(element, context);
        return true;
      },
      new Set()
    );
    return found;
  }

  function walkRoots(root, context, visit) {
    if (visit(root, context) === true) return true;
    const descendants = queryAll(root, "*");
    for (const node of descendants) {
      if (!(node instanceof HTMLElement)) continue;
      if (node.shadowRoot && walkRoots(node.shadowRoot, context, visit) === true) return true;
      if (node.tagName === "IFRAME") {
        const frameContext = getFrameContext(node, context);
        if (frameContext && walkRoots(frameContext.root, frameContext.context, visit) === true) return true;
      }
    }
    return false;
  }

  function deepElementFromPoint(root, globalX, globalY, context = createContext(null, 0, 0)) {
    const localX = globalX - context.offsetX;
    const localY = globalY - context.offsetY;
    const element = typeof root.elementFromPoint === "function" ? root.elementFromPoint(localX, localY) : null;
    if (!(element instanceof HTMLElement)) return null;
    if (element.shadowRoot) {
      const shadowHit = deepElementFromPoint(element.shadowRoot, globalX, globalY, context);
      if (shadowHit) return shadowHit;
    }
    if (element.tagName === "IFRAME") {
      const frameContext = getFrameContext(element, context);
      if (frameContext) {
        const frameHit = deepElementFromPoint(frameContext.root, globalX, globalY, frameContext.context);
        if (frameHit) return frameHit;
      }
    }
    return buildTargetInfo(element, context, { x: globalX, y: globalY });
  }

  function buildTargetInfo(element, context, preferredPoint = null) {
    if (!(element instanceof HTMLElement)) return null;
    const rect = visibleRectInContext(element, context);
    const point = preferredPoint || centerOfElementInContext(element, context);
    if (!rect && !point) return null;
    const localPoint = {
      x: clamp(Math.round((point?.x ?? 0) - context.offsetX), 0, Math.max(0, getContextViewportWidth(element))),
      y: clamp(Math.round((point?.y ?? 0) - context.offsetY), 0, Math.max(0, getContextViewportHeight(element)))
    };
    return {
      element,
      context,
      point,
      localPoint,
      rect,
      tag: element.tagName.toLowerCase(),
      role: element.getAttribute("role") || inferRole(element),
      type: element.getAttribute("type") || "",
      text: compactText(elementText(element), 180),
      selector: buildSelector(element),
      disabled: isDisabled(element),
      frameChain: context.frameChain.map((frame) => buildSelector(frame)).filter(Boolean)
    };
  }

  function createContext(frameElement, offsetX, offsetY, parentContext = null) {
    const frameChain = parentContext?.frameChain ? parentContext.frameChain.slice() : [];
    if (frameElement instanceof HTMLElement) frameChain.push(frameElement);
    return {
      frameChain,
      offsetX: Number(offsetX) || 0,
      offsetY: Number(offsetY) || 0
    };
  }

  function getFrameContext(frameElement, parentContext) {
    if (!(frameElement instanceof HTMLIFrameElement)) return null;
    try {
      const root = frameElement.contentDocument;
      const frameWindow = frameElement.contentWindow;
      if (!root || !frameWindow) return null;
      const rect = frameElement.getBoundingClientRect();
      return {
        root,
        context: createContext(
          frameElement,
          parentContext.offsetX + rect.left,
          parentContext.offsetY + rect.top,
          parentContext
        )
      };
    } catch {
      return null;
    }
  }

  function queryAll(root, selector) {
    try {
      return Array.from(root.querySelectorAll(selector));
    } catch {
      return [];
    }
  }

  function safeQuery(root, selector) {
    try {
      return root.querySelector(selector);
    } catch {
      return null;
    }
  }

  function dispatchMouseSequence(element, x, y) {
    const view = element.ownerDocument?.defaultView || window;
    const base = { bubbles: true, cancelable: true, view, clientX: x, clientY: y, button: 0 };
    const pointerBase = { ...base, pointerId: 1, pointerType: "mouse", isPrimary: true };
    element.dispatchEvent(new PointerEvent("pointerover", { ...pointerBase, buttons: 0 }));
    element.dispatchEvent(new MouseEvent("mouseover", base));
    element.dispatchEvent(new PointerEvent("pointermove", { ...pointerBase, buttons: 0 }));
    element.dispatchEvent(new MouseEvent("mousemove", base));
    element.dispatchEvent(new PointerEvent("pointerdown", { ...pointerBase, buttons: 1 }));
    element.dispatchEvent(new MouseEvent("mousedown", base));
    element.dispatchEvent(new PointerEvent("pointerup", { ...pointerBase, buttons: 0 }));
    element.dispatchEvent(new MouseEvent("mouseup", base));
    element.dispatchEvent(new MouseEvent("click", base));
  }

  function setEditableValue(element, value) {
    const tag = element.tagName.toLowerCase();
    const prototype = tag === "textarea" ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype;
    const descriptor = Object.getOwnPropertyDescriptor(prototype, "value");
    if (descriptor?.set) descriptor.set.call(element, value);
    else element.value = value;
    element.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertText", data: value }));
    element.dispatchEvent(new Event("change", { bubbles: true }));
  }

  function focusNext(direction) {
    const focusables = Array.from(document.querySelectorAll(INTERACTIVE_SELECTOR))
      .filter((node) => node instanceof HTMLElement && !isDisabled(node) && isVisibleInContext(node, createContext(null, 0, 0)));
    if (!focusables.length) return;
    const currentIndex = focusables.indexOf(document.activeElement);
    const nextIndex = currentIndex < 0
      ? 0
      : (currentIndex + direction + focusables.length) % focusables.length;
    focusables[nextIndex].focus?.();
  }

  function buildSelector(element) {
    if (!(element instanceof Element)) return "";
    const ownerDocument = element.ownerDocument || document;
    if (element.id) {
      const escapedId = cssEscape(element.id);
      try {
        if (ownerDocument.querySelectorAll(`#${escapedId}`).length === 1) return `#${escapedId}`;
      } catch {}
    }
    const attrs = ["data-testid", "data-e2e", "data-role", "aria-label", "name", "placeholder", "title"];
    for (const attr of attrs) {
      const value = element.getAttribute(attr);
      if (!value) continue;
      const selector = `${element.tagName.toLowerCase()}[${attr}="${cssAttr(value)}"]`;
      try {
        if (ownerDocument.querySelectorAll(selector).length === 1) return selector;
      } catch {}
    }
    const parts = [];
    let current = element;
    while (current && current.nodeType === Node.ELEMENT_NODE && current !== ownerDocument.documentElement) {
      const tag = current.tagName.toLowerCase();
      const parent = current.parentElement;
      if (!parent) {
        parts.unshift(tag);
        break;
      }
      const sameTag = Array.from(parent.children).filter((child) => child.tagName === current.tagName);
      const index = sameTag.indexOf(current) + 1;
      parts.unshift(sameTag.length > 1 ? `${tag}:nth-of-type(${index})` : tag);
      if (parts.length >= 6) break;
      current = parent;
    }
    return parts.join(" > ");
  }

  function describeElement(element) {
    if (!(element instanceof Element)) return null;
    const context = locateElementContext(element) || createContext(null, 0, 0);
    const info = buildTargetInfo(element, context);
    return info ? {
      tag: info.tag,
      role: info.role,
      text: compactText(elementText(element), 120),
      selector: info.selector,
      disabled: info.disabled,
      rect: info.rect,
      frameChain: info.frameChain
    } : null;
  }

  function locateElementContext(element) {
    if (!(element instanceof HTMLElement)) return null;
    const chain = [];
    let frameWindow = element.ownerDocument?.defaultView || window;
    while (frameWindow && frameWindow !== window) {
      try {
        const frameElement = frameWindow.frameElement;
        if (!(frameElement instanceof HTMLIFrameElement)) break;
        chain.unshift(frameElement);
        frameWindow = frameElement.ownerDocument?.defaultView || window;
      } catch {
        break;
      }
    }
    let offsetX = 0;
    let offsetY = 0;
    let parentContext = createContext(null, 0, 0);
    for (const frame of chain) {
      const rect = frame.getBoundingClientRect();
      offsetX += rect.left;
      offsetY += rect.top;
      parentContext = createContext(frame, offsetX, offsetY, parentContext);
    }
    return parentContext;
  }

  function elementText(element) {
    if (!(element instanceof Element)) return "";
    if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
      return element.value || element.placeholder || element.getAttribute("aria-label") || element.name || "";
    }
    return element.getAttribute("aria-label")
      || element.getAttribute("title")
      || element.textContent
      || "";
  }

  function inferRole(element) {
    const tag = element.tagName.toLowerCase();
    if (tag === "button") return "button";
    if (tag === "a") return "link";
    if (tag === "input" || tag === "textarea") return "textbox";
    if (tag === "select") return "combobox";
    return "";
  }

  function isEditableElement(element) {
    return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement;
  }

  function isButtonLike(element) {
    const tag = element.tagName.toLowerCase();
    return tag === "button" || tag === "a" || element.getAttribute("role") === "button";
  }

  function isDisabled(element) {
    return Boolean(element.disabled || element.getAttribute("aria-disabled") === "true");
  }

  function isVisibleInContext(element, context) {
    const ownerWindow = element.ownerDocument?.defaultView || window;
    const style = ownerWindow.getComputedStyle(element);
    if (style.display === "none" || style.visibility === "hidden" || Number(style.opacity) === 0) return false;
    const rect = element.getBoundingClientRect();
    if (rect.width <= 0 || rect.height <= 0) return false;
    const globalLeft = rect.left + context.offsetX;
    const globalTop = rect.top + context.offsetY;
    const globalRight = rect.right + context.offsetX;
    const globalBottom = rect.bottom + context.offsetY;
    return globalBottom >= 0 && globalRight >= 0 && globalTop <= window.innerHeight && globalLeft <= window.innerWidth;
  }

  function visibleRectInContext(element, context) {
    const rect = element.getBoundingClientRect();
    const left = clamp(rect.left + context.offsetX, 0, window.innerWidth);
    const top = clamp(rect.top + context.offsetY, 0, window.innerHeight);
    const right = clamp(rect.right + context.offsetX, 0, window.innerWidth);
    const bottom = clamp(rect.bottom + context.offsetY, 0, window.innerHeight);
    const width = Math.max(0, right - left);
    const height = Math.max(0, bottom - top);
    if (!width || !height) return null;
    return {
      x: Math.round(left),
      y: Math.round(top),
      width: Math.round(width),
      height: Math.round(height)
    };
  }

  function centerOfElementInContext(element, context) {
    const rect = element.getBoundingClientRect();
    return {
      x: Math.round(clamp(rect.left + context.offsetX + rect.width / 2, 0, Math.max(0, window.innerWidth))),
      y: Math.round(clamp(rect.top + context.offsetY + rect.height / 2, 0, Math.max(0, window.innerHeight)))
    };
  }

  function getContextViewportWidth(element) {
    const view = element.ownerDocument?.defaultView || window;
    return Math.max(0, view.innerWidth || window.innerWidth);
  }

  function getContextViewportHeight(element) {
    const view = element.ownerDocument?.defaultView || window;
    return Math.max(0, view.innerHeight || window.innerHeight);
  }

  function normalizeAction(value) {
    return String(value || "").trim().toLowerCase().replace(/-/g, "_");
  }

  function compactText(value, limit) {
    const text = String(value || "").replace(/\s+/g, " ").trim();
    return text.length > limit ? `${text.slice(0, limit - 1)}...` : text;
  }

  function cssEscape(value) {
    if (window.CSS?.escape) return window.CSS.escape(String(value));
    return String(value).replace(/[^a-zA-Z0-9_-]/g, "\\$&");
  }

  function cssAttr(value) {
    return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
  }

  function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
  }

  function delay(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  function isObject(value) {
    return Boolean(value) && typeof value === "object" && !Array.isArray(value);
  }
})();
