(() => {
  if (window.__MRP_PICKER__) {
    return;
  }

  const MEDIA_EXTENSIONS = /\.(3g2|3gp|aac|apng|avif|avi|bmp|flac|gif|jpe?g|m3u8|m4a|m4s|m4v|mkv|mov|mp3|mp4|mpeg|mpd|oga|ogg|ogv|png|svg|ts|wav|webm|webp)(\?|#|$)/i;
  const BLOCKED_SCHEMES = /^(data|blob|chrome|chrome-extension|edge):/i;
  const MIN_SIZE = 96;
  const OVERLAY_SIZE = 22;
  const OVERLAY_GAP = 6;
  const MIN_VISIBLE_EDGE = 40;
  const AUTO_MIN_ITEMS = 4;
  const AUTO_CHECK_MS = 1500;
  const DETAIL_VIDEO_HEIGHT_RATIO = 0.58;

  const state = {
    enabled: false,
    overlays: new Map(),
    selected: new Map(),
    observer: null,
    raf: 0,
    style: null,
    toolbar: null,
    menu: null,
    options: null,
    autoMode: false,
    autoPausedUntil: 0
  };

  window.__MRP_PICKER__ = { enable, disable, refresh };

  chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
    if (message?.type === "MRP_TOGGLE_PICKER") {
      const next = typeof message.enabled === "boolean" ? message.enabled : !state.enabled;
      next ? enable(false) : disable(true);
      sendResponse({ ok: true, enabled: state.enabled, count: state.selected.size });
      return;
    }

    if (message?.type === "MRP_GET_PICKER_STATE") {
      sendResponse({ ok: true, enabled: state.enabled, count: state.selected.size });
    }
  });

  setTimeout(runAutoMode, 500);
  setInterval(runAutoMode, AUTO_CHECK_MS);

  function enable(autoMode = false) {
    if (state.enabled) {
      state.autoMode = Boolean(autoMode);
      refresh();
      return;
    }
    state.enabled = true;
    state.autoMode = Boolean(autoMode);
    ensureStyle();
    ensureToolbar();
    refresh();
    window.addEventListener("scroll", schedule, true);
    window.addEventListener("resize", schedule);
    state.observer = new MutationObserver(schedule);
    state.observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true });
  }

  function disable(pauseAuto = false) {
    state.enabled = false;
    if (pauseAuto) {
      state.autoPausedUntil = Date.now() + 60000;
    }
    window.removeEventListener("scroll", schedule, true);
    window.removeEventListener("resize", schedule);
    state.observer?.disconnect();
    state.raf && cancelAnimationFrame(state.raf);
    state.observer = null;
    state.raf = 0;
    state.overlays.forEach((overlay) => overlay.remove());
    state.overlays.clear();
    state.toolbar?.remove();
    state.menu?.remove();
    state.style?.remove();
    state.toolbar = null;
    state.menu = null;
    state.options = null;
    state.autoMode = false;
    state.style = null;
  }

  function refresh() {
    if (!state.enabled) {
      return;
    }
    if (state.autoMode && !shouldAutoEnable()) {
      disable(false);
      return;
    }

    const items = collectItems();
    const liveIds = new Set(items.map((item) => item.id));

    for (const [id, overlay] of state.overlays) {
      if (!liveIds.has(id)) {
        overlay.remove();
        state.overlays.delete(id);
      }
    }

    for (const item of items) {
      let overlay = state.overlays.get(item.id);
      if (!overlay) {
        overlay = makeOverlay(item);
        state.overlays.set(item.id, overlay);
        document.body.append(overlay);
      }
      overlay.__mrpItem = item;
      overlay.querySelector("input").checked = state.selected.has(item.id);
      place(overlay, item.element);
    }

    updateToolbar();
  }

  function collectItems() {
    const items = [];
    const seen = new Set();

    for (const element of document.querySelectorAll("img,video,audio")) {
      const tag = element.tagName.toLowerCase();
      const kind = tag === "img" ? "image" : tag === "audio" ? "audio" : "video";
      addItem(items, seen, element, mediaUrl(element), kind);
    }

    for (const link of document.querySelectorAll("a[href]")) {
      if (MEDIA_EXTENSIONS.test(link.href)) {
        addItem(items, seen, link, link.href, kindFromUrl(link.href));
      }
    }

    return items;
  }

  function addItem(items, seen, element, rawUrl, kind) {
    const url = absolutize(rawUrl);
    const rect = element.getBoundingClientRect();
    if (!element.isConnected || !url || BLOCKED_SCHEMES.test(url) || seen.has(url) || !visible(rect)) {
      return;
    }
    const id = hash(url);
    seen.add(url);
    items.push({
      id,
      url,
      kind,
      name: fileName(url),
      extension: extension(url),
      pageTitle: document.title || "media-resources",
      source: "page-picker",
      element
    });
  }

  function runAutoMode() {
    if (Date.now() < state.autoPausedUntil) {
      return;
    }

    const allowed = shouldAutoEnable();
    if (allowed && !state.enabled) {
      enable(true);
    } else if (!allowed && state.enabled && state.autoMode) {
      disable(false);
    }
  }

  function shouldAutoEnable() {
    if (hasDominantVideo()) {
      return false;
    }
    return collectItems().length >= AUTO_MIN_ITEMS;
  }

  function hasDominantVideo() {
    if (document.fullscreenElement) {
      return true;
    }

    for (const video of document.querySelectorAll("video")) {
      const rect = video.getBoundingClientRect();
      if (
        rect.width >= MIN_SIZE &&
        rect.height >= window.innerHeight * DETAIL_VIDEO_HEIGHT_RATIO &&
        rect.bottom > 0 &&
        rect.right > 0
      ) {
        return true;
      }
    }
    return false;
  }

  function makeOverlay(item) {
    const label = document.createElement("label");
    label.className = "mrp-picker-box";
    label.title = "选择下载";
    label.addEventListener("click", stopBubble, true);
    label.addEventListener("mousedown", stopBubble, true);

    const input = document.createElement("input");
    input.type = "checkbox";
    input.setAttribute("aria-label", "选择下载");
    input.addEventListener("change", () => {
      const current = label.__mrpItem || item;
      if (input.checked) {
        warmElement(current.element);
        state.selected.set(current.id, { ...plain(current), selectedAt: Date.now() });
      } else {
        state.selected.delete(current.id);
      }
      state.options = null;
      state.menu?.remove();
      state.menu = null;
      updateToolbar();
    });

    label.append(input, document.createElement("span"));
    return label;
  }

  function ensureToolbar() {
    if (state.toolbar) {
      return;
    }

    const toolbar = document.createElement("div");
    toolbar.className = "mrp-picker-toolbar";
    toolbar.innerHTML = '<span data-count>已选 0</span><button type="button" data-action="choose">选择下载</button><button type="button" data-action="clear">清空</button><button type="button" data-action="close">退出</button>';
    toolbar.addEventListener("click", onToolbarClick);
    document.body.append(toolbar);
    state.toolbar = toolbar;
  }

  async function onToolbarClick(event) {
    const action = event.target?.dataset?.action;
    const downloadType = event.target?.dataset?.downloadType;
    if (!action && !downloadType) {
      return;
    }
    stop(event);

    if (downloadType) {
      await downloadResolved(downloadType);
      return;
    }
    if (action === "close") {
      disable(true);
      return;
    }
    if (action === "clear") {
      state.selected.clear();
      state.options = null;
      state.menu?.remove();
      state.menu = null;
      refresh();
      return;
    }
    if (action === "choose" && state.selected.size) {
      await openDownloadMenu();
    }
  }

  async function openDownloadMenu() {
    warmSelected();
    const button = state.toolbar.querySelector('[data-action="choose"]');
    button.disabled = true;
    button.textContent = "解析中";
    await delay(600);
    const response = await chrome.runtime.sendMessage({
      type: "RESOLVE_PAGE_SELECTIONS",
      items: [...state.selected.values()]
    }).catch(() => ({ ok: false }));
    button.disabled = false;
    button.textContent = "选择下载";
    if (!response.ok) {
      toast("没有解析到可下载资源");
      return;
    }
    state.options = response.options || {};
    renderDownloadMenu();
  }

  async function downloadResolved(type) {
    const items = state.options?.[type] || [];
    if (!items.length) {
      toast("该类型没有可下载资源");
      return;
    }
    const response = await chrome.runtime.sendMessage({ type: "DOWNLOAD_SELECTED", items }).catch(() => ({ ok: false }));
    toast(response.ok ? `已提交 ${items.length} 个下载` : "下载失败");
  }

  function renderDownloadMenu() {
    state.menu?.remove();
    const menu = document.createElement("div");
    menu.className = "mrp-picker-menu";
    const choices = [
      ["video", "视频", state.options.video || []],
      ["audio", "音频", state.options.audio || []],
      ["image", "图片", state.options.image || []]
    ];
    const usable = choices.filter((choice) => choice[2].length);
    if (!usable.length) {
      menu.textContent = "没有匹配到缓存素材";
    } else {
      for (const [type, label, items] of usable) {
        const button = document.createElement("button");
        button.type = "button";
        button.dataset.downloadType = type;
        button.textContent = `${label} (${items.length})`;
        menu.append(button);
      }
    }
    state.toolbar.append(menu);
    state.menu = menu;
  }

  function ensureStyle() {
    if (state.style) {
      return;
    }
    const style = document.createElement("style");
    style.textContent = `
      .mrp-picker-box{position:fixed!important;z-index:2147483646!important;display:grid!important;width:22px!important;height:22px!important;place-items:center!important;background:transparent!important;border:0!important;border-radius:6px!important;box-shadow:none!important;cursor:pointer!important}
      .mrp-picker-box input{position:absolute!important;width:1px!important;height:1px!important;opacity:0!important}
      .mrp-picker-box span{width:15px!important;height:15px!important;background:rgba(255,255,255,.5)!important;border:2px solid rgba(55,65,81,.88)!important;border-radius:4px!important;box-shadow:0 1px 5px rgba(15,23,42,.22)!important}
      .mrp-picker-box:hover span{background:rgba(255,255,255,.86)!important}
      .mrp-picker-box input:checked+span{background:#176bff!important;border-color:#176bff!important;box-shadow:inset 0 0 0 3px #fff,0 1px 5px rgba(15,23,42,.22)!important}
      .mrp-picker-toolbar{position:fixed!important;right:24px!important;bottom:24px!important;z-index:2147483647!important;display:flex!important;align-items:center!important;gap:8px!important;padding:10px!important;color:#172033!important;background:#fff!important;border:1px solid #d9dee7!important;border-radius:8px!important;box-shadow:0 10px 36px rgba(15,23,42,.22)!important;font:14px/1.2 "Segoe UI","Microsoft YaHei",sans-serif!important}
      .mrp-picker-toolbar button{height:32px!important;padding:0 12px!important;color:#172033!important;background:#f6f7f9!important;border:1px solid #d9dee7!important;border-radius:6px!important;cursor:pointer!important;font:inherit!important}
      .mrp-picker-toolbar [data-action=choose]{color:#fff!important;background:#176bff!important;border-color:#176bff!important}
      .mrp-picker-toolbar button:disabled{opacity:.55!important;cursor:not-allowed!important}
      .mrp-picker-menu{position:absolute!important;right:0!important;bottom:54px!important;display:flex!important;gap:8px!important;padding:8px!important;color:#172033!important;background:#fff!important;border:1px solid #d9dee7!important;border-radius:8px!important;box-shadow:0 10px 30px rgba(15,23,42,.2)!important;white-space:nowrap!important}
      .mrp-picker-toast{position:fixed!important;right:24px!important;bottom:78px!important;z-index:2147483647!important;padding:9px 12px!important;color:#fff!important;background:#111827!important;border-radius:7px!important;font:13px/1.2 "Segoe UI","Microsoft YaHei",sans-serif!important}
    `;
    document.documentElement.append(style);
    state.style = style;
  }

  function updateToolbar() {
    if (!state.toolbar) {
      return;
    }
    state.toolbar.querySelector("[data-count]").textContent = `已选 ${state.selected.size}`;
    state.toolbar.querySelector('[data-action="choose"]').disabled = state.selected.size === 0;
  }

  function place(overlay, element) {
    const placement = placementFor(element);
    if (!placement) {
      overlay.hidden = true;
      return;
    }

    overlay.hidden = false;
    overlay.style.top = `${placement.top}px`;
    overlay.style.left = `${placement.left}px`;
  }

  function schedule() {
    if (!state.enabled || state.raf) {
      return;
    }
    state.raf = requestAnimationFrame(() => {
      state.raf = 0;
      refresh();
    });
  }

  function mediaUrl(element) {
    if (element.tagName.toLowerCase() === "img") {
      return element.currentSrc || element.src;
    }
    return element.currentSrc || element.src || element.querySelector("source")?.src;
  }

  function visible(rect) {
    const viewportWidth = viewportValue("Width");
    const viewportHeight = viewportValue("Height");
    const visibleWidth = Math.min(rect.right, viewportWidth) - Math.max(rect.left, 0);
    const visibleHeight = Math.min(rect.bottom, viewportHeight) - Math.max(rect.top, 0);
    return (
      rect.width >= MIN_SIZE &&
      rect.height >= MIN_SIZE &&
      visibleWidth >= Math.min(MIN_VISIBLE_EDGE, rect.width) &&
      visibleHeight >= Math.min(MIN_VISIBLE_EDGE, rect.height)
    );
  }

  function placementFor(element) {
    if (!element?.isConnected) {
      return null;
    }

    const rect = element.getBoundingClientRect();
    if (!visible(rect)) {
      return null;
    }

    const viewportWidth = viewportValue("Width");
    const viewportHeight = viewportValue("Height");
    const left = clamp(rect.right - OVERLAY_SIZE - OVERLAY_GAP, OVERLAY_GAP, viewportWidth - OVERLAY_SIZE - OVERLAY_GAP);
    const top = clamp(rect.top + OVERLAY_GAP, OVERLAY_GAP, viewportHeight - OVERLAY_SIZE - OVERLAY_GAP);
    const centerX = left + OVERLAY_SIZE / 2;
    const centerY = top + OVERLAY_SIZE / 2;

    return pointBelongsToElement(element, centerX, centerY) ? { left, top } : null;
  }

  function pointBelongsToElement(element, x, y) {
    const nodes = document.elementsFromPoint ? document.elementsFromPoint(x, y) : [document.elementFromPoint(x, y)].filter(Boolean);
    const container = element.closest?.("a,button,li,article,[role='listitem'],[class*='card'],[class*='item']");

    for (const node of nodes) {
      if (isPickerNode(node) || node === document.documentElement || node === document.body) {
        continue;
      }
      return node === element || element.contains(node) || node.contains(element) || Boolean(container?.contains(node));
    }
    return false;
  }

  function isPickerNode(node) {
    return Boolean(node.closest?.(".mrp-picker-box,.mrp-picker-toolbar,.mrp-picker-menu,.mrp-picker-toast"));
  }

  function viewportValue(axis) {
    return window[`inner${axis}`] || document.documentElement[`client${axis}`] || 0;
  }

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

  function plain(item) {
    const { element, ...data } = item;
    return data;
  }

  function warmSelected() {
    for (const overlay of state.overlays.values()) {
      if (state.selected.has(overlay.__mrpItem?.id)) {
        warmElement(overlay.__mrpItem.element);
      }
    }
  }

  function warmElement(element) {
    for (const type of ["pointerover", "mouseover", "mouseenter"]) {
      element.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, view: window }));
    }
  }

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

  function stop(event) {
    event.preventDefault();
    event.stopPropagation();
  }

  function stopBubble(event) {
    event.stopPropagation();
  }

  function toast(text) {
    document.querySelector(".mrp-picker-toast")?.remove();
    const node = document.createElement("div");
    node.className = "mrp-picker-toast";
    node.textContent = text;
    document.body.append(node);
    setTimeout(() => node.remove(), 2200);
  }

  function absolutize(rawUrl) {
    try {
      return rawUrl ? new URL(rawUrl, location.href).href : "";
    } catch {
      return "";
    }
  }

  function extension(url) {
    try {
      const match = /\.([a-z0-9]{2,8})$/i.exec(decodeURIComponent(new URL(url).pathname));
      return match ? match[1].toLowerCase() : "";
    } catch {
      return "";
    }
  }

  function fileName(url) {
    try {
      return decodeURIComponent(new URL(url).pathname).split("/").filter(Boolean).pop() || `media-${Date.now()}`;
    } catch {
      return `media-${Date.now()}`;
    }
  }

  function kindFromUrl(url) {
    const ext = extension(url);
    if (/^(apng|avif|bmp|gif|jpe?g|png|svg|webp)$/i.test(ext)) {
      return "image";
    }
    if (/^(aac|flac|m4a|mp3|oga|ogg|wav)$/i.test(ext)) {
      return "audio";
    }
    return "video";
  }

  function hash(value) {
    let result = 0;
    for (let index = 0; index < value.length; index += 1) {
      result = (result * 31 + value.charCodeAt(index)) >>> 0;
    }
    return result.toString(36);
  }
})();
