"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var widgetContract_exports = {};
__export(widgetContract_exports, {
  default: () => widgetContract_default
});
module.exports = __toCommonJS(widgetContract_exports);
var import_mcpBundle = require("playwright-core/lib/mcpBundle");
var import_tool = require("./tool");
var import_widgetContract = require("../../../dom-analyzer/widgetContract");
const widgetContractLookup = (0, import_tool.defineTabTool)({
  capability: "core",
  schema: {
    name: "browser_widget_contract_lookup",
    title: "Look up a widget interaction contract by fingerprint",
    description: [
      "Returns the interaction contract for a widget's fingerprint.",
      "",
      "Only call for elements whose `widgetType` is `custom` or `unknown` \u2014 native widgets don't",
      "need contracts. Pass the element's ref along with the fingerprint.",
      "",
      'On `status: "needs_inference"`, synthesize a WidgetContract from your own reasoning using',
      "the returned context (outerHtml, ancestor chain, aria subtree, optional portal candidate),",
      "submit it via `browser_widget_contract_cache`, then execute the contract using existing",
      "browser tools (`browser_click`, `browser_type`, etc.).",
      "",
      'On `status: "error", reason: "stale_ref"`, re-snapshot and retry.',
      "",
      'On `status: "error", reason: "context_gather_failed"`, inspect the message; the error may be transient (retry) or structural (give up and try a different ref).',
      "",
      "Do not speculatively pre-infer contracts \u2014 call only when about to interact."
    ].join("\n"),
    inputSchema: import_mcpBundle.z.object({
      fingerprint: import_mcpBundle.z.string().regex(/^[0-9a-f]{16}$/).describe("16-hex fingerprint from the element's PageBlueprint entry"),
      ref: import_mcpBundle.z.string().describe('Snapshot ref for the specific element instance (e.g. "e42")')
    }),
    type: "readOnly"
  },
  handle: async (tab, params, response) => {
    const { fingerprint, ref } = params;
    const pure = (0, import_widgetContract.lookupContract)(fingerprint, tab.context.inferredContracts);
    if (pure.status === "found") {
      response.addTextResult(JSON.stringify({ status: "found", contract: pure.contract }, null, 2));
      return;
    }
    let locator;
    try {
      ({ locator } = await tab.refLocator({ ref, element: "widget-fingerprint-target" }));
    } catch {
      response.addTextResult(JSON.stringify({ status: "error", reason: "stale_ref" }, null, 2));
      return;
    }
    let gather;
    let ariaRaw;
    try {
      gather = await locator.evaluate((el) => {
        function truncate(s, max) {
          return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
        }
        const outerHtml = truncate(el.outerHTML, 2048);
        const ancestorChain = [];
        let cur = el.parentElement;
        let depth = 0;
        while (cur && depth < 8) {
          const role = cur.getAttribute("role");
          const tag = cur.tagName.toLowerCase();
          ancestorChain.push(role ? `${tag}[role='${role}']` : tag);
          if (tag === "body") break;
          cur = cur.parentElement;
          depth++;
        }
        let portalEl = null;
        const ctrl = el.getAttribute("aria-controls");
        if (ctrl) {
          const t = document.getElementById(ctrl);
          if (t && !el.contains(t)) portalEl = t;
        }
        if (!portalEl) {
          let found = 0;
          const walker = document.createTreeWalker(document.documentElement, NodeFilter.SHOW_ELEMENT);
          let cur2;
          while (cur2 = walker.nextNode()) {
            const desc = cur2;
            if (el.contains(desc)) continue;
            for (const attr of Array.from(desc.attributes)) {
              if (attr.name.startsWith("data-radix-") || attr.name.startsWith("data-headlessui-")) {
                portalEl = desc;
                break;
              }
            }
            if (portalEl) break;
            if (++found >= 20) break;
          }
        }
        const portal = portalEl ? {
          selector: portalEl.tagName.toLowerCase() + (portalEl.id ? `#${portalEl.id}` : ""),
          outerHtml: truncate(portalEl.outerHTML, 2048)
        } : void 0;
        return { outerHtml, ancestorChain, portal };
      });
      ariaRaw = await locator.ariaSnapshot();
    } catch (e) {
      response.addTextResult(JSON.stringify({
        status: "error",
        reason: "context_gather_failed",
        message: e.message
      }, null, 2));
      return;
    }
    const ariaSnapshot = ariaRaw.length <= 1024 ? ariaRaw : ariaRaw.slice(0, 1023) + "\u2026";
    const result = {
      status: "needs_inference",
      fingerprint,
      ref,
      element: { outerHtml: gather.outerHtml, ancestorChain: gather.ancestorChain },
      ariaSnapshot,
      ...gather.portal ? { portalCandidate: gather.portal } : {}
    };
    response.addTextResult(JSON.stringify(result, null, 2));
  }
});
const widgetContractCache = (0, import_tool.defineTabTool)({
  capability: "core",
  schema: {
    name: "browser_widget_contract_cache",
    title: "Cache an inferred widget contract",
    description: [
      "Writes an inferred widget contract into the session's cache.",
      "",
      "Refuses to overwrite curated entries. Mutable for inferred entries \u2014 resubmit to",
      'correct a bad inference. Submit a contract with `source: "unknown"` and empty steps',
      "to mark the fingerprint as unresolvable for the session.",
      "",
      "Execute the contract yourself after a successful write; the tool does not return it back."
    ].join("\n"),
    inputSchema: import_mcpBundle.z.object({
      fingerprint: import_mcpBundle.z.string().regex(/^[0-9a-f]{16}$/).describe("16-hex fingerprint of the widget being cached \u2014 must match the fingerprint that browser_widget_contract_lookup returned in needs_inference status (or that you read from a PageBlueprint element's fingerprint field)."),
      // InferredWidgetContractSchema (not WidgetContractSchema): narrows
      // `source` to {'inferred','unknown'}. Curated contracts come only
      // from the curated library — agents must not be able to mislabel an
      // inferred entry as authoritative via this tool surface.
      contract: import_widgetContract.InferredWidgetContractSchema.describe(`The widget's interaction contract. Set source to "inferred" for a real contract you authored, or "unknown" with empty steps to mark the widget as unresolvable for this session. Curated contracts come from the library \u2014 you cannot submit source: "curated".`)
    }),
    type: "readOnly"
  },
  handle: async (tab, params, response) => {
    const { fingerprint, contract } = params;
    const result = (0, import_widgetContract.cacheInferredContract)(fingerprint, contract, tab.context.inferredContracts);
    response.addTextResult(JSON.stringify(result));
  }
});
var widgetContract_default = [widgetContractLookup, widgetContractCache];
