(function () {
  'use strict';

  // 工具方法
  function getDomainFromUrlString(urlString) {
    if (!urlString) {
      return;
    }
    if (!urlString.includes("://")) {
      urlString = "http://" + urlString;
    }
    try {
      const url = new URL(urlString);
      return url.hostname;
    } catch (error) {
      return "";
    }
  }
  function getFallbackLangValue() {
    return navigator?.language?.includes("zh")
      ? "zh"
      : navigator?.language?.includes("ja")
      ? "ja"
      : navigator?.language?.includes("ko")
      ? "ko"
      : "en";
  }

  // 内建站点列表
  const defaultWebsites = [
    {
      i18n: "zhongGuoZhanDian",
      value: "https://boardmix.cn",
      api: "https://api.boardmix.cn",
    },
    {
      i18n: "haiWaiZhanDian",
      value: "https://boardmix.com",
      api: "https://api.boardmix.com",
    },
  ];
  function getFallbackWebsite() {
    return navigator?.language?.includes("zh")
      ? defaultWebsites[0]
      : defaultWebsites[1];
  }

  // 监听站点切换
  let selectedWebsite;
  const watchStoragedSelectedWebsiteCallback = (storagedSelectedWebsite) => {
    if (storagedSelectedWebsite) {
      selectedWebsite = JSON.parse(storagedSelectedWebsite);
    } else {
      selectedWebsite = getFallbackWebsite();
    }
  };
  watchStoragedSelectedWebsite(watchStoragedSelectedWebsiteCallback);

  // 监听cookie变化，广播给所有watch方法.
  const cookieKeyDepMap = new Map();
  chrome?.cookies?.onChanged?.addListener((changeInfo) => {
    if (!selectedWebsite) {
      return;
    }
    const domain = getDomainFromUrlString(selectedWebsite.value);
    if (
      changeInfo.cookie.domain === domain &&
      ["expired_overwrite", "explicit"].includes(changeInfo.cause)
    ) {
      console.log(changeInfo, changeInfo.cookie.name);
      const dep = cookieKeyDepMap.get(changeInfo.cookie.name);
      const newValue =
        changeInfo.cause === "expired_overwrite" ||
        (changeInfo.cause === "explicit" && changeInfo.removed)
          ? undefined
          : changeInfo.cookie.value;
      dep?.callbacks && dep.callbacks.forEach((item) => item(newValue));
    }
  });

  // 监听storage变化，广播给所有watch方法.
  const storageKeyDepMap = new Map();
  chrome?.storage?.onChanged?.addListener((changes, namespace) => {
    for (let [key, { oldValue, newValue }] of Object.entries(changes)) {
      const dep = storageKeyDepMap.get(key);
      dep?.callbacks && dep.callbacks.forEach((item) => item(newValue));
    }
  });
  const watchStorage = (key, callback) => {
    let dep = storageKeyDepMap.get(key);
    if (!dep) {
      dep = {};
      storageKeyDepMap.set(key, dep);
    }
    if (!dep.callbacks) {
      dep.callbacks = [];
    }
    dep.callbacks.push(callback);
  };

  // selectedLang
  async function getStoragedSelectedLang() {
    const result = await chrome?.storage?.local?.get(["selectedLang"]);
    return result?.selectedLang;
  }
  async function watchStoragedSelectedLang(callback) {
    callback(await getStoragedSelectedLang());
    watchStorage("selectedLang", callback);
  }

  // disableDragSave
  async function getStoragedDisableDragSave() {
    const result = await chrome?.storage?.local?.get(["disableDragSave"]);
    return result?.disableDragSave;
  }
  async function watchStoragedDisableDragSave(callback) {
    callback(await getStoragedDisableDragSave());
    watchStorage("disableDragSave", callback);
  }

  // disableHoverSave
  async function getStoragedDisableHoverSave() {
    const result = await chrome?.storage?.local?.get(["disableHoverSave"]);
    return result?.disableHoverSave;
  }
  async function watchStoragedDisableHoverSave(callback) {
    callback(await getStoragedDisableHoverSave());
    watchStorage("disableHoverSave", callback);
  }

  // selectedWebsite
  async function getStoragedSelectedWebsite() {
    const result = await chrome?.storage?.local?.get(["selectedWebsite"]);
    return result?.selectedWebsite;
  }
  async function watchStoragedSelectedWebsite(callback) {
    callback(await getStoragedSelectedWebsite());
    watchStorage("selectedWebsite", callback);
  }

  var localeZh = {
    wEBChaJian: "web插件_",
    wuCaoZuoCiZi: "无操作此资源权限，保存失败",
    qiYeKongJianBu: "企业空间不一致，保存失败",
    neiRongWeiGuiBao: "内容违规，保存失败",
    suoXuanKongJianRong: "所选空间容量不足，保存失败",
    baoCunShiBai: "保存失败",
    yiChengGongBaoCun: "已成功保存至素材库",
    baoCunZhong: "保存中...",
    tuPian: "图片",
    wenBen: "文本",
    lianJie: "链接",
    caiJiWenBen: "采集文字到Boardmix素材库",
    caiJiTuPian: "采集图片到Boardmix素材库",
    caiJiLianJie: "采集链接到Boardmix素材库",
    baoCunDaoSuCai: "保存到素材库失败",
    qingQiuShiBai: "请求失败",
    chaJianWeiDengLu: "插件未登录，请登录后使用",
    collect: "收藏",
    tagOversize: "标签数超过限制",
  };

  var localeEn = {
    wEBChaJian: "webPlugin_",
    wuCaoZuoCiZi: "No permission to operate this resource, save failed.",
    qiYeKongJianBu: "Workspace inconsistency, save failed.",
    neiRongWeiGuiBao: "Content violation, save failed.",
    suoXuanKongJianRong:
      "Insufficient storage of selected workspace, save failed.",
    baoCunShiBai: "Save failed",
    yiChengGongBaoCun: "saved to Boardmix resource library",
    baoCunZhong: "Saving...",
    tuPian: "Image",
    wenBen: "Text",
    lianJie: "URL",
    caiJiWenBen: "Capture text to Boardmix resource library",
    caiJiTuPian: "Capture the image to Boardmix resource library",
    caiJiLianJie: "Capture the URL to Boardmix resource library",
    baoCunDaoSuCai: "Failed to save to Boardmix resource library",
    qingQiuShiBai: "Request failed",
    chaJianWeiDengLu: "You are not logged in. Please log in to use the plugin.",
    collect: "Favorite",
    tagOversize: "Exceeded tag limit",
  };

  var localeJa = {
    wEBChaJian: "webプラグイン_",
    wuCaoZuoCiZi: "このリソース権限を操作せず、保存に失敗しました",
    qiYeKongJianBu: "エンタープライズスペースが一致せず、保存に失敗しました",
    neiRongWeiGuiBao: "コンテンツ違反、保存失敗",
    suoXuanKongJianRong: "選択したスペースの容量が不足し、保存に失敗しました",
    baoCunShiBai: "保存に失敗しました",
    yiChengGongBaoCun: "素材中継所への保存に成功しました",
    baoCunZhong: "保存中…",
    tuPian: "ピクチャー",
    wenBen: "テキスト",
    lianJie: "リンク",
    caiJiWenBen: "Boardmix素材中継所にテキストの取得",
    caiJiTuPian: "Boardmix素材中継所に画像を収集",
    caiJiLianJie: "Boardmix素材中継所にリンクの取得",
    baoCunDaoSuCai: "素材中継所に保存できなかった",
    qingQiuShiBai: "リクエスト失敗",
    chaJianWeiDengLu:
      "プラグインはログインしていません。ログインしてから使用してください",
    collect: "お気に入り",
    tagOversize: "タグの制限を超える",
  };

  var localeKo = {
    wEBChaJian: "웹 플러그인_",
    wuCaoZuoCiZi: "해당 리소스를 편집할 수 있는 권한이 없습니다. 저장에 실패했습니다.",
    qiYeKongJianBu: "기업 공간이 일치하지 않아 저장에 실패했습니다.",
    neiRongWeiGuiBao: "위반 내용이 있어 저장할 수 없습니다.",
    suoXuanKongJianRong: "선택한 공간 용량이 부족하여 저장에 실패했습니다.",
    baoCunShiBai: "저장할 수 없습니다.",
    yiChengGongBaoCun: "Boardmix 소재 라이브러리에 저장했습니다.",
    baoCunZhong: "저장 중...",
    tuPian: "이미지",
    wenBen: "텍스트",
    lianJie: "링크",
    caiJiWenBen: "Boardmix 소재 라이브러리에 텍스트 저장",
    caiJiTuPian: "Boardmix 소재 라이브러리에 사진 저장",
    caiJiLianJie: "Boardmix 소재 라이브러리에 링크 저장",
    baoCunDaoSuCai: "소재 라이브러리에 저장할 수 없습니다.",
    qingQiuShiBai: "요청 실패했습니다.",
    chaJianWeiDengLu:
      "플러그인이 로그인되지 않았습니다. 로그인한 후 사용하십시오",
    collect: "즐겨찾기",
    tagOversize: "태그 제한을 초과했습니다",
  };

  const observePopstate = () => {
    window.onpopstate = function(event) {
      hide();
    };
  };

  let disableHoverSave = false;
  const watchStoragedDisableHoverSaveCallback = (value) => {
    disableHoverSave = value === true;
  };
  watchStoragedDisableHoverSave(watchStoragedDisableHoverSaveCallback);

  // 监听鼠标事件
  const observeMouse = () => {
    document.body.addEventListener("mouseover", onMouseover);
    document.body.addEventListener("mouseout", onMouseout);
  };
  let collectIcon = undefined;
  function isCollectIconVisible() {
    const icon = getCollectIcon();
    return icon.style.visibility !== "hidden";
  }

  function getCollectIcon() {
    if (!collectIcon) {
      collectIcon = document.createElement("div");
      collectIcon.setAttribute(
        "style",
        [
          "position: absolute",
          "top: 0",
          "left: 0",
          "visibility: hidden",
          "padding: 4px 6px 4px 6px",
          "box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2)",
          "border-radius: 6px",
          "background-color: white",
          "display: flex",
          "justify-content: center",
          "align-items: center",
          "gap: 4px",
          "cursor: pointer",
          "z-index: 99999999",
        ].join("!important;")
      );
      collectIcon.innerHTML = `<img style="pointer-events: none;" src="chrome-extension://mlnlaiakmeajemgjfdkkfhophfeimhah/images/icon16.png"><span style="line-height: 1em;pointer-events: none; font-size: 12px;">${I18N.collect}</span>`;
      collectIcon.addEventListener("click", function (event) {
        if (targetImage.src) {
          const type = "image";
          const content = targetImage.src;
          window.dispatchEvent(
            new CustomEvent("bm-plugin-drag-finish", {
              detail: {
                type,
                content,
              },
            })
          );
        }
      });
      document.body.appendChild(collectIcon);
    }
    return collectIcon;
  }

  let targetImage = undefined;
  function onMouseover(event) {
    const targetElement = event.target;
    const icon = getCollectIcon();
    if (targetElement === icon) {
      window.clearTimeout(window.delayHide);
      return;
    }
    if (
      targetElement.tagName === "IMG" &&
      targetElement.width > 100 &&
      targetElement.height > 100 &&
      targetElement.src.match(/^((http|https):\/\/)/)
    ) {
      if (disableHoverSave) {
        return
      }
      targetImage = targetElement;
      window.clearTimeout(window.delayHide);
      const rect = targetElement.getBoundingClientRect();
      const topOffset = rect.top + window.scrollY;
      const leftOffset = rect.left + window.scrollX;
      icon.style.visibility = "visible";
      icon.style.top = topOffset + 8 + "px";
      icon.style.left = leftOffset + 8 + "px";
    }
  }

  function hide() {
    window.clearTimeout(window.delayHide);
    window.delayHide = window.setTimeout(() => {
      const icon = getCollectIcon();
      icon.style.visibility = "hidden";
    }, 100);
  }

  function onMouseout(event) {
    if (isCollectIconVisible()) {
      const targetElement = event.target;
      const icon = getCollectIcon();
      if (targetElement !== icon) {
        hide();
      }
    }
  }

  // 多语言支持
  let I18N;
  const localeMap = {
    zh: localeZh,
    en: localeEn,
    ja: localeJa,
    ko: localeKo,
  };
  let selectedLangValue;
  const watchStoragedSelectedLangCallback = (storagedSelectedLang) => {
    if (storagedSelectedLang) {
      selectedLangValue = JSON.parse(storagedSelectedLang).value;
      I18N = localeMap[selectedLangValue] ?? localeMap[getFallbackLangValue()];
    } else {
      selectedLangValue = getFallbackLangValue();
      I18N = localeMap[getFallbackLangValue()];
    }
    window.dispatchEvent(
      new CustomEvent("bmp-plugin-lang-update", {
        detail: selectedLangValue,
      })
    );
  };
  watchStoragedSelectedLang(watchStoragedSelectedLangCallback);

  const getBase64ImageSize = async (imageBase64) => {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = function () {
        resolve({ width: img.width, height: img.height });
      };
      img.src = imageBase64;
    });
  };

  chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    if (message.target === "content") {
      if (message.origin === "popup") {
        switch (message.payload.value) {
          case "link": {
            handleLink();
            break;
          }
          case "saveLink": {
            handleSaveLink(message.payload);
            break;
          }
          case "screenshot": {
            handleCapture();
            break;
          }
          case "scrollCapture": {
            handleScrollCapture();
            break;
          }
          case "cancelScrollCapture": {
            handleCancelScrollCapture();
            break;
          }
          case "startCrawse": {
            startCrawseImage();
            break;
          }
          case "stopCrawse": {
            stopCrawseImage();
            break;
          }
          case "showToast": {
            window.dispatchEvent(
              new CustomEvent("bmp-plugin-toast-show", {
                detail: message.payload.data,
              })
            );
            break;
          }
          case "exit": {
            handleExit();
            break;
          }
        }
      } else if (message.origin === "background") {
        switch (message.payload.value) {
          case "thumbnail": {
            getThumbnail(
              message.payload.data,
              message.payload.id,
              message.payload.mime
            );
            break;
          }
          case "proxyAccess": {
            waitingMap[message.payload.id] = message.payload.data;
            break;
          }
          case "togglePopup": {
            togglePopup();
            break;
          }
          case "showToast": {
            window.dispatchEvent(
              new CustomEvent("bmp-plugin-toast-show", {
                detail: message.payload.data,
              })
            );
            break;
          }
          case "getBase64ImageSize": {
            getBase64ImageSize(message.payload.data).then((data) => {
              sendResponse(data);
            });
            return true;
          }
        }
      }
    }
  });

  const waitingMap = {};
  const pipline = (value, id, data, ms, max) => {
    const origin = "content";
    const target = "background";
    return new Promise((resolve, reject) => {
      globalThis?.chrome?.runtime.sendMessage({
        origin,
        target,
        payload: {
          value,
          id,
          data,
        },
      });
      let count = 0;
      const runloop = () => {
        setTimeout(() => {
          count = count + 1;
          if (waitingMap[id]) {
            resolve(waitingMap[id]);
          } else if (count > max) {
            reject("timeout");
          } else {
            runloop();
          }
        }, ms);
      };
      runloop();
    });
  };

  const handleExit = () => {
    globalThis?.chrome?.runtime.sendMessage({
      origin: "content",
      target: "background",
      payload: {
        value: "exit",
      },
    });
  };

  const handleLink = async () => {
    removeCaptureArea();
    if (document.getElementById("bm-inject-link-preview")) {
      return;
    }
    injectLinkPreview();
    const target = window.location.href;
    const reponse = await pipline(
      "proxyAccess",
      new Date().getTime(),
      target,
      100,
      80
    );
    const data = reponse.data;
    data.url = target;
    window.dispatchEvent(
      new CustomEvent("bmp-plugin-link-preview", {
        detail: data,
      })
    );
  };

  // 注入popup页面
  const togglePopup = (state) => {
    let iframe = document.getElementById("bm-inject-popup");
    function onMessage(e) {
      if (e.data.event === "resize") {
        iframe.style.width = e.data.width + "px";
        iframe.style.height = e.data.height + "px";
      }
    }
    if (!iframe) {
      iframe = document.createElement("iframe");
      iframe.id = "bm-inject-popup";
      iframe.src = "chrome-extension://mlnlaiakmeajemgjfdkkfhophfeimhah/index.html";
      iframe.style.position = "fixed";
      iframe.style.top = "8px";
      iframe.style.right = "8px";
      iframe.style.width = "0px";
      iframe.style.height = "0px";
      iframe.style.border = "none";
      iframe.style.zIndex = "999999";
      document.body.appendChild(iframe);
      window.addEventListener("message", onMessage);
    } else {
      iframe.style.display = "none";
      document.body.removeChild(iframe);
      window.removeEventListener("message", onMessage);
    }
  };

  // 注入预览页（需求已去除）
  const injectLinkPreview = (screenshot) => {
    fetch(chrome.runtime.getURL("src/views/link/index.html"))
      .then((response) => response.text())
      .then((html) => {
        const div = document.createElement("div");
        div.id = "bm-inject-link-preview";
        div.innerHTML = html;
        document.body.appendChild(div);

        const parser = new DOMParser();
        const doc = parser.parseFromString(html, "text/html");
        const scripts = doc.querySelectorAll("script");

        // 遍历所有的 script 标签，将其内容设置为要执行的脚本代码
        const promises = [];
        for (const script of scripts) {
          const newScript = document.createElement("script");
          newScript.src = script.src + "?" + "time=" + new Date().getTime();
          newScript.type = script.type;
          document.body.appendChild(newScript);
          promises.push(
            new Promise((resolve, reject) => {
              newScript.onload = function () {
                document.body.removeChild(newScript);
                resolve();
              };
            })
          );
        }

        Promise.all(promises).then(() => {
          document.getElementById("bm-plugin-screenshot-img") &&
            (document.getElementById("bm-plugin-screenshot-img").src =
              screenshot);
        });
      });
  };

  const removeLinkPreview = () => {
    const element = document.getElementById("bm-inject-link-preview");
    if (element) {
      element.style.display = "none";
      document.body.removeChild(element);
    }
  };

  const handleSaveLink = (payload) => {
    removeLinkPreview();
    globalThis?.chrome?.runtime.sendMessage({
      origin: "content",
      target: "background",
      payload: {
        value: "uploadFile",
        data: {
          type: "link",
          content: location.href,
          file_name: payload.data.title ?? globalThis?.document?.title,
          tags: payload.data.tags,
          remark: payload.data.remark,
        },
      },
    });
  };

  const handleCapture = async () => {
    removeLinkPreview();
    if (document.getElementById("bm-inject-capture-area")) {
      return;
    }
    hidePopup();
    await sleep(100);
    const data = await globalThis?.chrome?.runtime.sendMessage({
      origin: "content",
      target: "background",
      payload: {
        value: "screenshot",
      },
    });
    injectCaptureArea(data);
  };

  let styleElement = undefined;
  function getTargetArea() {
    // 如果body有滚动区域，则直接滚动body。
    if (
      document.body.parentElement.scrollHeight -
        document.body.parentElement.clientHeight >
      30
    ) {
      return document.body.parentElement;
    }

    // 获取当前网页内所有元素
    const elements = document.querySelectorAll("*");
    let maxWidth = 0;
    let maxElement = undefined;
    // 遍历网页中的元素
    elements.forEach((element) => {
      const overflowY = window.getComputedStyle(element).overflowY;
      if (
        element.clientWidth >= maxWidth &&
        element.scrollHeight > element.clientHeight &&
        (overflowY === "scroll" || overflowY === "auto")
      ) {
        maxWidth = element.clientWidth;
        maxElement = element;
      }
    });
    if (!maxElement) {
      maxElement = document.body;
    }
    return maxElement;
  }

  // 恢复所有元素的透明度
  function unsetElementsTransparent() {
    // 遍历文档中的所有元素
    const elements = document.getElementsByTagName("*");
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      element.classList.remove("bm-plugin-transparent-element");
    }
  }

  // 将除某元素以外的元素设置成透明。
  function setElementsTransparentExcept(targetElement) {
    // 遍历文档中的所有元素
    const elements = document.getElementsByTagName("*");
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      // 排除目标元素及其父子元素
      if (
        (element !== targetElement &&
          !targetElement.contains(element) &&
          !element.contains(targetElement)) ||
        (["sticky", "fixed"].includes(getComputedStyle(element).position) &&
          !element.contains(targetElement))
      ) {
        !element.classList.contains("bm-plugin-transparent-element") &&
          element.classList.add("bm-plugin-transparent-element");
      }
    }
  }

  // 隐藏popup。这里单独成对
  function hidePopup() {
    const popup = document.getElementById("bm-inject-popup");
    popup.style.opacity = 0;
  }
  function showPopup() {
    const popup = document.getElementById("bm-inject-popup");
    popup.style.opacity = 1;
  }

  async function getImageElement(base64Data) {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.src = base64Data;
      image.onload = function () {
        resolve(image);
      };
    });
  }

  // 对图片进行裁剪
  async function cropImage(imageData, y, height) {
    return new Promise((resolve, reject) => {
      const image = new Image();
      image.src = imageData;
      image.onload = function () {
        const canvas = document.createElement("canvas");
        const ctx = canvas.getContext("2d");
        canvas.width = image.width;
        canvas.height = height;
        ctx.drawImage(image, 0, 0 - y, image.width, image.height);
        const base64 = canvas.toDataURL("image/jpeg");
        resolve(base64);
      };
    });
  }

  async function sleep(ms) {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(), ms);
    });
  }

  // 截取element
  async function takeScreenshot(element, crop = false, hideOthers = false) {
    if (hideOthers) {
      setTimeout(() => {
        setElementsTransparentExcept(element);
      }, 400);
    }
    await sleep(800);
    let data = await globalThis?.chrome?.runtime.sendMessage({
      origin: "content",
      target: "background",
      payload: {
        value: "screenshot",
      },
    });
    const imageElement = await getImageElement(data);
    const rect = element.getBoundingClientRect();
    let isRootElement = false;
    // 如果是根元素，则忽略rect.top
    if (element === document.body.parentElement) {
      isRootElement = true;
    }
    if (crop) {
      data = await cropImage(
        data,
        isRootElement ? 0 : rect.top,
        element.clientHeight
      );
    }
    const image = {
      data,
      y: !crop ? 0 : element.scrollTop + (isRootElement ? 0 : rect.top),
      height: !crop ? imageElement.height : element.clientHeight,
    };
    return image;
  }

  // 抓取网页内所有图片
  let isCrawseing = false;
  function startCrawseImage() {
    isCrawseing = true;
    loopCrawseImage();
  }
  function loopCrawseImage() {
    const images = crawseImage();
    const iframe = document.getElementById("bm-inject-popup");
    if (iframe && isCrawseing) {
      iframe.contentWindow.postMessage(
        {
          event: 'crawseImage',
          images
        },
        '*'
      );
      setTimeout(() => {
        loopCrawseImage();
      }, 3000);
    }
  }
  function crawseImage() {
    // 获取当前网页内所有图片
    const imgs = document.querySelectorAll("img");
    // 挑出宽高大于100的url告知popup
    const result = [];
    for (const img of imgs) {
      if (
        img.width > 100 &&
        img.height > 100 &&
        img.src.match(/^((http|https):\/\/)/)
      ) {
        result.push(img.src);
      }
    }
    return result;
  }
  function stopCrawseImage() {
    isCrawseing = false;
  }

  let targetArea = undefined;
  let allScreenshots = undefined;
  const handleCancelScrollCapture = (hidePopup = false) => {
    resetScrollbar();
    window.removeEventListener("keydown", onKeydown);
    allScreenshots = undefined;
    !hidePopup && showPopup();
    unsetElementsTransparent();
    if (targetArea) {
      targetArea.classList.remove("bm-plugin-sroll-area");
      targetArea = undefined;
    }
  };

  function onKeydown(e) {
    if (allScreenshots?.length > 0 && e.key === "Escape") {
      onScrollCaptureFinish();
    }
  }

  async function onScrollCaptureFinish() {
    await globalThis?.chrome?.storage?.local?.set({
      allScreenshots: allScreenshots,
    });
    // 截图完成 打开新窗口
    handleCancelScrollCapture(true);
    handleExit();
    globalThis?.chrome?.runtime.sendMessage({
      origin: "content",
      target: "background",
      payload: {
        value: "edit",
      },
    });
  }

  // 恢复scrollbar
  function resetScrollbar() {
    const style = document.getElementById("bm-plugin-hide-scrollbar");
    style && document.head.removeChild(style);
  }
  // 隐藏scrollbar
  function hideScrollbar() {
    const style = document.createElement("style");
    style.id = "bm-plugin-hide-scrollbar";
    style.innerHTML = "*::-webkit-scrollbar {display: none !important;}";
    document.head.appendChild(style);
  }

  const handleScrollCapture = async () => {
    if (!styleElement) {
      styleElement = document.createElement("style");
      styleElement.innerText =
        ".bm-plugin-sroll-area{ } \n .bm-plugin-transparent-element{ opacity: 0 !important; }";
      document.head.appendChild(styleElement);
    }

    // 先获取网页内纵向滚动区域最大的一块可滚动区域
    let newTargetArea = getTargetArea();
    if (newTargetArea !== targetArea) {
      handleCancelScrollCapture();
      targetArea = newTargetArea;
      targetArea.classList.add("bm-plugin-sroll-area");
      window.focus();
      window.addEventListener("keydown", onKeydown);
      // 隐藏所有滚动条
      hideScrollbar();

      // 滚动截屏基本工作原理，首先截取第一屏，然后截屏截取滚动区域进行拼接
      allScreenshots = [];
      hidePopup();
      targetArea.scrollTop = 0;
      allScreenshots.push(await takeScreenshot(targetArea));
      function scrollCapture() {
        if (allScreenshots === undefined) {
          // 本次滚动截图提前结束
          return;
        }
        if (
          targetArea.scrollHeight -
            targetArea.scrollTop -
            targetArea.clientHeight <
          5
        ) {
          onScrollCaptureFinish();
          return;
        }
        targetArea.scrollTop += targetArea.clientHeight;
        takeScreenshot(targetArea, true, true).then((image) => {
          if (allScreenshots) {
            allScreenshots.push(image);
            scrollCapture();
          }
        });
      }
      scrollCapture();
    }
  };

  const injectCaptureArea = (screenshot) => {
    fetch(chrome.runtime.getURL("src/views/capture/index.html"))
      .then((response) => response.text())
      .then((html) => {
        const div = document.createElement("div");
        div.id = "bm-inject-capture-area";
        div.innerHTML = html;
        document.body.appendChild(div);

        const parser = new DOMParser();
        const doc = parser.parseFromString(html, "text/html");
        const scripts = doc.querySelectorAll("script");

        // 遍历所有的 script 标签，将其内容设置为要执行的脚本代码
        const promises = [];
        for (const script of scripts) {
          const newScript = document.createElement("script");
          newScript.src = script.src + "?" + "time=" + new Date().getTime();
          newScript.type = script.type;
          document.body.appendChild(newScript);
          promises.push(
            new Promise((resolve, reject) => {
              newScript.onload = function () {
                document.body.removeChild(newScript);
                resolve();
              };
            })
          );
        }

        Promise.all(promises).then(() => {
          document.getElementById("bm-plugin-screenshot-img") &&
            (document.getElementById("bm-plugin-screenshot-img").src =
              screenshot);
        });
        setTimeout(() => {
          window.dispatchEvent(
            new CustomEvent("bmp-plugin-lang-update", {
              detail: selectedLangValue,
            })
          );
        }, 100);
      });
  };

  const removeCaptureArea = () => {
    const element = document.getElementById("bm-inject-capture-area");
    if (element) {
      element.style.display = "none";
      document.body.removeChild(element);
    }
  };

  const injectDragArea = () => {
    fetch(chrome.runtime.getURL("src/views/drag/index.html"))
      .then((response) => response.text())
      .then((html) => {
        const div = document.createElement("div");
        div.id = "bm-inject-drag-area";
        div.innerHTML = html;
        document.body.appendChild(div);

        const parser = new DOMParser();
        const doc = parser.parseFromString(html, "text/html");
        const scripts = doc.querySelectorAll("script");

        // 遍历所有的 script 标签，将其内容设置为要执行的脚本代码
        for (const script of scripts) {
          const newScript = document.createElement("script");
          newScript.src = script.src + "?" + "time=" + new Date().getTime();
          newScript.type = script.type;
          document.body.appendChild(newScript);
          newScript.onload = function () {
            document.body.removeChild(newScript);
            window.dispatchEvent(
              new CustomEvent("bmp-plugin-lang-update", {
                detail: selectedLangValue,
              })
            );
          };
        }
      });
  };

  const injectToastContainer = () => {
    fetch(chrome.runtime.getURL("src/views/toast/index.html"))
      .then((response) => response.text())
      .then((html) => {
        const div = document.createElement("div");
        div.id = "bm-inject-toast-container";
        div.innerHTML = html;
        document.body.appendChild(div);

        const parser = new DOMParser();
        const doc = parser.parseFromString(html, "text/html");
        const scripts = doc.querySelectorAll("script");

        // 遍历所有的 script 标签，将其内容设置为要执行的脚本代码
        for (const script of scripts) {
          const newScript = document.createElement("script");
          newScript.src = script.src + "?" + "time=" + new Date().getTime();
          newScript.type = script.type;
          document.body.appendChild(newScript);
          newScript.onload = function () {
            document.body.removeChild(newScript);
          };
        }
      });
  };

  let disableDragSave = false;
  const watchStoragedDisableDragSaveCallback = (value) => {
    disableDragSave = value === true;
  };
  watchStoragedDisableDragSave(watchStoragedDisableDragSaveCallback);

  const watchDragEvents = () => {
    window.addEventListener("dragstart", (e) => {
      if (disableDragSave) {
        return
      }
      const element = document.getElementById("bm-plugin-drag-app");
      if (e.dataTransfer.types.length > 0) {
        element.style.display = "block";
      }
    });

    window.addEventListener("dragend", (e) => {
      const element = document.getElementById("bm-plugin-drag-app");
      element.style.display = "none";
    });
  };

  const watchCustomEvents = () => {
    window.addEventListener("bmp-plugin-capture-finish", async (e) => {
      const imageElement = await getImageElement(e.detail.content);
      await globalThis?.chrome?.storage?.local?.set({
        allScreenshots: [
          {
            data: e.detail.content,
            y: 0,
            height: imageElement.height,
          },
        ],
      });
      removeCaptureArea();
      handleExit();
      globalThis?.chrome?.runtime.sendMessage({
        origin: "content",
        target: "background",
        payload: {
          value: "edit",
        },
      });
    });
    window.addEventListener("bm-plugin-drag-finish", (e) => {
      globalThis?.chrome?.runtime.sendMessage({
        origin: "content",
        target: "background",
        payload: {
          value: "uploadFile",
          id: new Date().getTime(),
          data: e.detail,
        },
      });
    });
    window.addEventListener("bmp-plugin-remove-link-preview", () => {
      removeLinkPreview();
    });
    window.addEventListener("bmp-plugin-remove-capture-area", () => {
      showPopup();
      removeCaptureArea();
    });
  };

  function blobToBase64(blob) {
    return new Promise((resolve, _) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result);
      reader.readAsDataURL(blob);
    });
  }

  const getThumbnail = (base64, id, mime) => {
    const image = document.createElement("img");
    image.onload = () => {
      // 生成缩略图
      let scale = 1;
      if (image.width > 256 || image.height > 256) {
        scale = Math.min(256 / image.width, 256 / image.height);
      }
      if (scale < 1) {
        const canvas = document.createElement("canvas");
        canvas.width = image.width * scale;
        canvas.height = image.height * scale;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
        canvas.toBlob((b) => {
          blobToBase64(b).then((data) => {
            globalThis?.chrome?.runtime.sendMessage({
              origin: "content",
              target: "background",
              payload: {
                value: "thumbnail",
                id,
                data,
              },
            });
          });
        }, mime);
      } else {
        globalThis?.chrome?.runtime.sendMessage({
          origin: "content",
          target: "background",
          payload: {
            value: "thumbnail",
            id,
            data: base64,
          },
        });
      }
    };
    image.src = base64;
  };

  const timeoutCheckBody = () => {
    setTimeout(() => {
      if (document.body) {
        injectDragArea();
        injectToastContainer();
        watchDragEvents();
        watchCustomEvents();
        observeMouse();
        observePopstate();
      } else {
        timeoutCheckBody();
      }
    }, 500);
  };
  timeoutCheckBody();

})();
