/**
 * P0：Autocomplete 实例拓扑 + place_changed 监听器指纹
 * P2：全局 fetch 劫持（axel/location/place）
 * 纯字符串 initScript，供 addInitScript 注入。
 */

export const P0_PLACE_DIAG_INIT = `(() => {
  if (window.__rpaPlaceDiagP0) return;
  window.__rpaPlaceDiagP0 = true;
  window.__rpaPlaceDiag = window.__rpaPlaceDiag || {
    instances: [],
    listeners: [],
    events: [],
    fetchLog: [],
    mark: "init",
    nextInstanceId: 1,
    nextListenerId: 1,
  };
  var diag = window.__rpaPlaceDiag;

  function inputMeta(el) {
    if (!el) return null;
    var gmKeys = Object.keys(el).filter(function(k) { return k.indexOf("gm_") === 0; });
    return {
      tagName: el.tagName || "",
      id: el.id || "",
      className: (el.className || "").slice(0, 80),
      placeholder: el.placeholder || "",
      pacTarget: el.classList && el.classList.contains("pac-target-input"),
      valuePreview: ((el.value || el.textContent || "") + "").replace(/\\s+/g, " ").trim().slice(0, 100),
      gmKeyCount: gmKeys.length,
      gmKeys: gmKeys.slice(0, 6),
    };
  }

  function resolveInstanceFromInput(el) {
    if (!el) return null;
    for (var i = 0; i < Object.keys(el).length; i += 1) {
      var key = Object.keys(el)[i];
      if (key.indexOf("gm_") !== 0) continue;
      var val = el[key];
      if (val && typeof val.getPlace === "function") return val;
    }
    for (var j = 0; j < diag.instances.length; j += 1) {
      if (diag.instances[j].inputEl === el) return diag.instances[j].instance;
    }
    return null;
  }

  function instanceIdFor(inst, inputEl) {
    for (var i = 0; i < diag.instances.length; i += 1) {
      if (diag.instances[i].instance === inst) return diag.instances[i].id;
    }
    var id = "ac-" + diag.nextInstanceId++;
    diag.instances.push({
      id: id,
      instance: inst,
      inputEl: inputEl || inst.__rpaInputEl || null,
      input: inputMeta(inputEl || inst.__rpaInputEl || null),
      createdAt: Date.now(),
      listenerIds: [],
    });
    return id;
  }

  function fingerprintHandler(handler, source) {
    var src = "";
    try { src = Function.prototype.toString.call(handler); } catch (e) { src = String(handler); }
    var compact = src.replace(/\\s+/g, " ").trim();
    return {
      source: source,
      length: compact.length,
      preview: compact.slice(0, 240),
      hasFetch: /\\bfetch\\s*\\(/.test(compact),
      hasAxelPlace: /axel\\/location\\/place/.test(compact),
      hasGetPlace: /getPlace\\s*\\(/.test(compact),
      hasXMLHttpRequest: /XMLHttpRequest|\\.open\\s*\\(/.test(compact),
    };
  }

  function safeGetPlace(inst) {
    if (!inst || typeof inst.getPlace !== "function") {
      return { ok: false, reason: "no-getPlace" };
    }
    try {
      var p = inst.getPlace();
      if (!p) return { ok: true, empty: true };
      var loc = p.geometry && p.geometry.location;
      var lat = null;
      var lng = null;
      if (loc) {
        lat = typeof loc.lat === "function" ? loc.lat() : loc.lat;
        lng = typeof loc.lng === "function" ? loc.lng() : loc.lng;
      }
      return {
        ok: true,
        place_id: p.place_id || null,
        formatted_address: (p.formatted_address || "").slice(0, 160),
        name: (p.name || "").slice(0, 80),
        hasGeometry: Boolean(loc),
        lat: lat,
        lng: lng,
      };
    } catch (e2) {
      return { ok: false, reason: "getPlace-threw", error: String(e2) };
    }
  }

  function wrapHandler(inst, handler, source, inputEl) {
    var instId = instanceIdFor(inst, inputEl);
    var fp = fingerprintHandler(handler, source);
    var lid = "lh-" + diag.nextListenerId++;
    diag.listeners.push({
      id: lid,
      instanceId: instId,
      registeredAt: Date.now(),
      fingerprint: fp,
    });
    for (var i = 0; i < diag.instances.length; i += 1) {
      if (diag.instances[i].id === instId) {
        diag.instances[i].listenerIds.push(lid);
        break;
      }
    }
    return function wrappedPlaceChangedHandler() {
      diag.events.push({
        type: "place_changed_handler",
        mark: diag.mark,
        at: Date.now(),
        instanceId: instId,
        listenerId: lid,
        fingerprint: fp,
        getPlaceBefore: safeGetPlace(inst),
      });
      return handler.apply(this, arguments);
    };
  }

  function registerPlaceChanged(inst, handler, source, inputEl) {
    if (!inst || typeof handler !== "function") return handler;
    return wrapHandler(inst, handler, source, inputEl);
  }

  window.__rpaAutocompleteInstances = window.__rpaAutocompleteInstances || [];
  window.__rpaPlaceChangedHandlers = window.__rpaPlaceChangedHandlers || [];

  var waitForGoogle = function() {
    if (typeof google === "undefined" || !google.maps || !google.maps.places || !google.maps.places.Autocomplete) {
      setTimeout(waitForGoogle, 200);
      return;
    }
    if (window.__rpaAutocompletePatched) return;
    window.__rpaAutocompletePatched = true;

    var AutocompleteCtor = google.maps.places.Autocomplete;
    google.maps.places.Autocomplete = function() {
      var args = arguments;
      var instance = Reflect.construct(AutocompleteCtor, args);
      var inputEl = args[0] || null;
      instance.__rpaInputEl = inputEl;
      window.__rpaAutocompleteInstances.push(instance);
      instanceIdFor(instance, inputEl);

      if (typeof instance.addListener === "function") {
        var origInstAdd = instance.addListener.bind(instance);
        instance.addListener = function(eventName, handler) {
          var h = handler;
          if (eventName === "place_changed" && typeof handler === "function") {
            h = registerPlaceChanged(instance, handler, "instance.addListener", inputEl);
            window.__rpaPlaceChangedHandlers.push({ instance: instance, handler: h, inputEl: inputEl });
          }
          return origInstAdd(eventName, h);
        };
      }
      return instance;
    };
    google.maps.places.Autocomplete.prototype = AutocompleteCtor.prototype;

    if (google.maps.event && typeof google.maps.event.addListener === "function") {
      var origMapsAdd = google.maps.event.addListener;
      google.maps.event.addListener = function(instance, eventName, handler) {
        var h = handler;
        if (
          eventName === "place_changed" &&
          instance &&
          typeof instance.getPlace === "function" &&
          typeof handler === "function"
        ) {
          h = registerPlaceChanged(instance, handler, "maps.event.addListener", instance.__rpaInputEl || null);
          window.__rpaPlaceChangedHandlers.push({
            instance: instance,
            handler: h,
            inputEl: instance.__rpaInputEl || null,
          });
        }
        return origMapsAdd(instance, eventName, h);
      };
    }

    if (google.maps.event && typeof google.maps.event.trigger === "function") {
      var origTrigger = google.maps.event.trigger;
      google.maps.event.trigger = function(instance, eventName) {
        var instId = instance && typeof instance.getPlace === "function"
          ? instanceIdFor(instance, instance.__rpaInputEl || null)
          : null;
        if (eventName === "place_changed") {
          diag.events.push({
            type: "maps_event_trigger",
            mark: diag.mark,
            at: Date.now(),
            instanceId: instId,
            getPlaceAtTrigger: instance ? safeGetPlace(instance) : null,
          });
        }
        return origTrigger.apply(this, arguments);
      };
    }

    diag.events.push({ type: "p0-ready", at: Date.now(), mark: diag.mark });
  };
  waitForGoogle();
})();`;

export const P2_FETCH_HIJACK_INIT = `(() => {
  if (window.__rpaPlaceFetchP2) return;
  window.__rpaPlaceFetchP2 = true;
  window.__rpaPlaceDiag = window.__rpaPlaceDiag || { fetchLog: [], events: [], mark: "init" };
  var diag = window.__rpaPlaceDiag;
  diag.fetchLog = diag.fetchLog || [];

  var origFetch = window.fetch;
  if (typeof origFetch === "function") {
    window.fetch = function() {
      var url = "";
      try {
        var first = arguments[0];
        url = typeof first === "string" ? first : (first && first.url) || "";
      } catch (e) {}
      if (url && url.indexOf("axel/location/place") >= 0) {
        var stack = "";
        try { stack = (new Error("place-fetch")).stack || ""; } catch (e2) {}
        diag.fetchLog.push({
          mark: diag.mark,
          at: Date.now(),
          url: url.slice(0, 240),
          stackPreview: stack.split("\\n").slice(0, 8).join(" | "),
        });
        diag.events.push({ type: "fetch_place", mark: diag.mark, at: Date.now(), url: url.slice(0, 240) });
      }
      return origFetch.apply(this, arguments);
    };
  }

  var XHR = window.XMLHttpRequest;
  if (XHR && XHR.prototype && XHR.prototype.open) {
    var origOpen = XHR.prototype.open;
    XHR.prototype.open = function(method, url) {
      this.__rpaUrl = url;
      return origOpen.apply(this, arguments);
    };
    var origSend = XHR.prototype.send;
    XHR.prototype.send = function() {
      var url = this.__rpaUrl || "";
      if (url && String(url).indexOf("axel/location/place") >= 0) {
        diag.fetchLog.push({
          mark: diag.mark,
          at: Date.now(),
          url: String(url).slice(0, 240),
          transport: "xhr",
        });
        diag.events.push({ type: "xhr_place", mark: diag.mark, at: Date.now(), url: String(url).slice(0, 240) });
      }
      return origSend.apply(this, arguments);
    };
  }
})();`;

/** 设置诊断阶段标记并清空本阶段事件 */
export const PLACE_DIAG_SET_MARK = `(mark) => {
  window.__rpaPlaceDiag = window.__rpaPlaceDiag || { events: [], mark: "init" };
  window.__rpaPlaceDiag.mark = mark || "phase";
  return { ok: true, mark: window.__rpaPlaceDiag.mark };
}`;

/** 采集实例拓扑 + 监听器指纹 + 事件 + fetch 日志（可序列化） */
export const PLACE_DIAG_COLLECT_SNAPSHOT = `() => {
  try {
  var diag = window.__rpaPlaceDiag;
  if (!diag) return { ok: false, reason: "no-diag" };

  function inputMeta(el) {
    if (!el) return null;
    var gmKeys = Object.keys(el).filter(function(k) { return k.indexOf("gm_") === 0; });
    return {
      tagName: el.tagName || "",
      placeholder: el.placeholder || "",
      pacTarget: el.classList && el.classList.contains("pac-target-input"),
      valuePreview: ((el.value || "") + "").replace(/\\s+/g, " ").trim().slice(0, 100),
      gmKeyCount: gmKeys.length,
    };
  }

  function resolveFromInput(el) {
    if (!el) return null;
    for (var i = 0; i < Object.keys(el).length; i += 1) {
      var key = Object.keys(el)[i];
      if (key.indexOf("gm_") !== 0) continue;
      var val = el[key];
      if (val && typeof val.getPlace === "function") return val;
    }
    return null;
  }

  var widget = document.querySelector("#react-quoter-landing-plugin");
  var inputProbes = [];
  if (widget) {
    var inputs = widget.querySelectorAll("input[type='text'], input:not([type])");
    for (var i = 0; i < inputs.length; i += 1) {
      var inp = inputs[i];
      var inst = resolveFromInput(inp);
      inputProbes.push({
        index: i,
        meta: inputMeta(inp),
        hasGmInstance: Boolean(inst),
        getPlace: inst && typeof inst.getPlace === "function"
          ? (function() {
              try {
                var p = inst.getPlace();
                return {
                  place_id: p && p.place_id,
                  formatted_address: p && p.formatted_address,
                  hasGeometry: Boolean(p && p.geometry && p.geometry.location),
                };
              } catch (e) { return { error: String(e) }; }
            })()
          : null,
      });
    }
  }

  var instances = (diag.instances || []).map(function(row) {
    var inst = row.instance;
    var getPlace = null;
    if (inst && typeof inst.getPlace === "function") {
      try {
        var p = inst.getPlace();
        getPlace = {
          place_id: p && p.place_id,
          formatted_address: p && p.formatted_address,
          hasGeometry: Boolean(p && p.geometry && p.geometry.location),
        };
      } catch (e2) {
        getPlace = { error: String(e2) };
      }
    }
    var listenerRows = (diag.listeners || []).filter(function(l) { return l.instanceId === row.id; });
    return {
      id: row.id,
      input: row.input,
      listenerCount: listenerRows.length,
      listenerFingerprints: listenerRows.map(function(l) { return l.fingerprint; }),
      getPlace: getPlace,
    };
  });

  var anyListenerHasFetch = (diag.listeners || []).some(function(l) {
    return l.fingerprint && l.fingerprint.hasFetch;
  });
  var anyListenerHasAxel = (diag.listeners || []).some(function(l) {
    return l.fingerprint && l.fingerprint.hasAxelPlace;
  });

  var handlerEvents = (diag.events || []).filter(function(e) {
    return e.type === "place_changed_handler" || e.type === "maps_event_trigger";
  });
  var fetchEvents = (diag.fetchLog || []).slice(-20);

  return {
    ok: true,
    mark: diag.mark,
    topology: {
      instanceCount: instances.length,
      instances: instances,
      inputProbes: inputProbes,
      monkeyPatchInstances: (window.__rpaAutocompleteInstances || []).length,
      capturedHandlers: (window.__rpaPlaceChangedHandlers || []).length,
    },
    listeners: {
      total: (diag.listeners || []).length,
      anyHasFetch: anyListenerHasFetch,
      anyHasAxelPlace: anyListenerHasAxel,
      rows: (diag.listeners || []).map(function(l) {
        return { id: l.id, instanceId: l.instanceId, fingerprint: l.fingerprint };
      }),
    },
    events: (diag.events || []).slice(-40),
    handlerEvents: handlerEvents,
    fetchLog: fetchEvents,
    activeElement: (function() {
      var el = document.activeElement;
      if (!el) return null;
      return inputMeta(el);
    })(),
  };
  } catch (err) {
    return { ok: false, reason: "snapshot-error", error: String(err) };
  }
}`;
