巴哈姆特_新版B頁板務功能Re

巴哈姆特哈拉區新體驗。

// ==UserScript==
// @name 巴哈姆特_新版B頁板務功能Re
// @namespace Bee10301
// @version 9.5
// @description 巴哈姆特哈拉區新體驗。
// @author Bee10301
// @match https://removed.www.gamer.com.tw/
// @match https://removed.www.gamer.com.tw/index2.php*
// @match https://forum.gamer.com.tw/B.php?*
// @match https://forum.gamer.com.tw/C.php?*
// @match https://forum.gamer.com.tw/2025/?bsn*
// @homepage https://home.gamer.com.tw/home.php?owner=bee10301
// @icon https://home.gamer.com.tw/favicon.ico
// @connect *
// @grant GM_xmlhttpRequest
// @license GPL
// ==/UserScript==

/**
 * 巴哈姆特插件 - 核心配置與初始化模組
 * 負責插件的基本配置、設定管理和初始化流程
 */
class BahamutePlugin {
  constructor() {
    this.version = "9.0";
    this.isNewVersion = false;
    this.settings = new SettingsManager();
    this.init();
  }

  /**
   * 插件初始化(舊版棄置)
   */
  async init() {
    try {
      this.isNewVersion = await this.detectMode();
      //this.settings.checkFirstRun();
      //await this.addSettingElement(this.isNewVersion);
      //await this.initializeWorkers();
      //this.checkTips(this.isNewVersion);
      //this.reportAlert(this.isNewVersion);
    } catch (error) {
      console.error("[ERROR] Plugin initialization failed:", error);
    }
  }

  /**
   * 檢測頁面模式(新版/舊版)
   * @returns {Promise<boolean>} 是否為新版
   */
  async detectMode() {
    if (document.querySelector(".forum-nav-main") !== null) {
      await this.waitForElement(".forum-list-normal");
      this.setupNewVersionStyles();
      return true;
    }
    return false;
  }

  /**
   * 等待特定元素出現
   * @param {string} selector - CSS選擇器
   */
  waitForElement(selector) {
    return new Promise((resolve) => {
      const observer = new MutationObserver((mutations) => {
        if (document.querySelector(selector)) {
          observer.disconnect();
          resolve();
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
    });
  }

  /**
   * 設置新版樣式
   */
  setupNewVersionStyles() {
    const styleSheet = document.createElement("style");
    document.head.appendChild(styleSheet);
    const sheet = styleSheet.sheet;

    // C頁管理工具樣式
    sheet.insertRule(
      ".c-section:has(div.c-section__main.managertools) { position: sticky; bottom: 0; right: 0; z-index: 100; transform: translateX(85%); transition: 0.5s cubic-bezier(0,.67,0,1.05); }",
      0
    );
    sheet.insertRule(
      ".c-section:has(div.c-section__main.managertools):hover { transform: translateX(0vw); }",
      0
    );
    // C頁避免誤點上一頁
    sheet.insertRule(".article-back { display: none !important; }", 0);
    // 快速回覆樣式
    sheet.insertRule(
      `.c-section:has(div.c-section__main.c-editor.c-quick-reply) { position: sticky; bottom: 50px; right: 0; z-index: 99; transform: translateX(85%); transition: 0.5s cubic-bezier(0,.67,0,1.05); }`,
      0
    );
    sheet.insertRule(
      ".c-section:has(div.c-section__main.c-editor.c-quick-reply):hover { transform: translateX(0vw); }",
      0
    );

    this.setupPreviewBox();
    this.setupTopBarCover();
  }

  /**
   * 設置預覽框
   */
  setupPreviewBox() {
    const previewBox = document.getElementById("article-content-box");
    if (!previewBox) return;

    previewBox.style.width = "0%";
    previewBox.style.transition = "0.5s cubic-bezier(0,.67,0,1.05)";
    previewBox.style.zIndex = "999";
    previewBox.style.transform =
      this.settings.get("preview_LR") === "true"
        ? "translateX(100%)"
        : "translateX(-150%)";
  }

  /**
   * 設置頂部遮罩
   */
  setupTopBarCover() {
    const topBarCover = document.createElement("div");
    topBarCover.className = "bee-top-bar-cover";

    Object.assign(topBarCover.style, {
      width: "100vw",
      height: "0%",
      backgroundColor: "var(--f1-bg)",
      position: "absolute",
      top: "0",
      left: "0",
      transition: "0.5s cubic-bezier(0,.67,0,1.05)",
      zIndex: "990",
    });

    topBarCover.addEventListener("click", (e) => {
      const previewBox = document.getElementById("article-content-box");
      if (previewBox) {
        previewBox.style.transform =
          this.settings.get("preview_LR") === "true"
            ? "translateX(100%)"
            : "translateX(-150%)";
      }
      // 棄用內建返回按鈕
      // if (
      //   window.getComputedStyle(document.querySelector(".article-back"))
      //     .display !== "none"
      // ) {
      //   document.querySelector(".article-back").click();
      // }

      // 將網址 snA sn cPage 參數移除
      const url = new URL(window.location.href);
      url.searchParams.delete("snA");
      url.searchParams.delete("sn");
      url.searchParams.delete("cPage");
      window.history.replaceState({}, "", url.toString());

      topBarCover.style.height = "0%";
      topBarCover.style.opacity = "1";
      // remove skip floor btn
      document.getElementById("floating-skip-button")?.remove();
      // remove quick replay
      document
        .querySelector(".article-content-box .c-editor.c-quick-reply")
        ?.remove();
      // remove managertools
      document.querySelector(".article-content-box .managertools")?.remove();
      return false;
    });

    const topBar = document.querySelector(".main-nav");
    if (topBar) {
      topBar.parentNode.insertBefore(topBarCover, topBar.nextSibling);
      document.querySelector(".main-nav__row").style.height = "auto";
    }
  }

  /**
   * 初始化工作模組
   */
  async initializeWorkers() {
    const bPageWorker = new BPageWorker(this.isNewVersion, this.settings);
    const cPageWorker = new CPageWorker(this.settings);

    await bPageWorker.init();
    await cPageWorker.init();
  }

  /**
   * 檢查提示
   */
  checkTips(newVer) {
    const tipsManager = new TipsManager(this.settings);
    tipsManager.checkTips(newVer);
  }

  /**
   * 檢查檢舉提醒
   */
  reportAlert(newVer) {
    const reportManager = new ReportManager(this.settings);
    reportManager.checkAlert(newVer);
  }
}

/**
 * 設定管理器
 */
class SettingsManager {
  constructor() {
    this.defaultSettings = this.getDefaultSettings();
  }

  /**
   * 獲取預設設定
   */
  getDefaultSettings() {
    return {
      isFirstRun: "false",
      add_function: "true",
      preview_auto: "true",
      preview_wait_load: "false",
      preview_size: "80%",
      new_design: "true",
      new_design_box: "80%",
      new_design_box_Left: "65%",
      new_design_box_Right: "18%",
      new_design_LRSwitch: "false",
      bee_select_color: "#000000b3",
      addBorderInPicMode: "true",
      showTips: "true",
      preview_LR: "true",
      showAbuse: "true",
      addSummaryBtn: "true",
      oaiBaseUrl: "https://api.openai.com/v1/chat/completions",
      oaiKey: "sk-yourKey",
      oaiModel: "gpt-3.5-turbo",
      oaiPrompt: `## workflow
1. 總結:精確的讀懂和理解文章,然後用一句話脈絡清晰的語句,總結出[文章的主旨]。
2. 提煉重點:根據文章的邏輯和結構,清楚列出文章的主要論點,並按照下方範例的格式輸出。

總結:
- 要點1:
- 要點2:
...(依情況增加或減少要點)

## MUST/IMPORTANT/RULES
- 不能添加其他個人觀點或註釋。
- 使用繁體中文`,
      oaiPromptCmd:
        "以下是一段群組聊天的對話,總結對話中的話題,用條列式列出使用者的想法。\n## workflow \n 1. 整理話題:理解各個使用者討論的話題並以話題為單位整理出整串對話的話題 \n 2. 將相同話題中,對同一件事有相似想法的對話整理在一起(例如 `@user1/@user2:認為太貴了`) ,不同看法則單獨列出。\n 3. 輸出:把冗餘贅字優化,但保留具體描述。(劣例:`@user1/@user2:提及角色在世界觀中的地位和特徵` 在這個例子中沒有具體描述提及了什麼樣的地位或特徵)。使用者以 @id 標記並且不再添加其他md語法。 \n ## MUST/IMPORTANT/RULES \n- 不能添加其他個人觀點或註釋。\n- 使用繁體中文\n",
      oaiPromptChat:
        "根據文章內容,使用繁體中文流暢語言,簡潔的回答使用者的問題。",
      custom_oaiPrompt: "",
      custom_oaiPromptCmd: "",
      custom_oaiPromptChat: "",
      oaiPromptSystemMode: "true",
      oaiPromptDate: "20241101",
      oaiPromptUpdateDate: "20241101",
      oaiPromptUpdateURL: "https://gamercomtwnew.bee.moe/gamer.prompts.json",
      oaiPromptUpdateSleep: "1",
      cleanMode: "false",
      cleanModeSize: "4rem",
      homeStyleSwitch: "true",
      homeTips: "true",
    };
  }

  /**
   * 檢查首次運行
   */
  checkFirstRun(reset = false) {
    console.log("[INFO] Init data");

    Object.entries(this.defaultSettings).forEach(([key, defaultValue]) => {
      if (this.get(key) === "" || this.get(key) === null || reset === true) {
        this.set(key, defaultValue);
      }
    });

    // 特殊處理:更新舊版URL
    if (
      this.get("oaiPromptUpdateURL") ===
      "https://gamercomtwnew.bee.moe/gamer.prompts.js"
    ) {
      this.set(
        "oaiPromptUpdateURL",
        "https://gamercomtwnew.bee.moe/gamer.prompts.json"
      );
    }
  }

  /**
   * 獲取設定值
   */
  get(key) {
    return localStorage.getItem(key);
  }

  /**
   * 設置設定值
   */
  set(key, value) {
    localStorage.setItem(key, value);
  }

  /**
   * 獲取布林值設定
   */
  getBool(key) {
    return this.get(key) === "true";
  }
}
/**
 * B頁面工作模組
 * 負責B頁面的所有功能,包括即時預覽、版面設計、功能按鈕等
 */
class BPageWorker {
  constructor(isNewVersion, settings) {
    this.isNewVersion = isNewVersion;
    this.settings = settings;
    this.previewFrame = null;
  }

  /**
   * 初始化B頁面功能
   */
  async init() {
    if (!this.isBPage()) return;

    await this.initializePreview();
    this.initializeLayout();
    this.initializeInteractions();
    this.initializeMenu();
    this.initializeDesign();
    this.initializeFunctions();
    this.initializeStyles();
  }

  /**
   * 檢查是否為B頁面
   */
  isBPage() {
    return (
      document.querySelector(".forum-list-normal") ||
      document.querySelector(".b-list__head")
    );
  }

  /**
   * 初始化預覽功能
   */
  async initializePreview() {
    await this.setupPreviewAuto();

    if (!this.isNewVersion && this.settings.getBool("preview_auto")) {
      await this.createPreviewFrame();
    }
  }

  /**
   * 設置自動預覽
   */
  async setupPreviewAuto() {
    if (this.isNewVersion) {
      await this.setupNewVersionPreview();
    } else {
      this.setupOldVersionPreview();
    }
  }

  /**
   * 設置新版預覽
   */
  async setupNewVersionPreview() {
    const articleListContainer = document.querySelector("#list");
    if (!articleListContainer) {
      console.warn("⚠️ 文章列表容器未找到!");
      return;
    }
    articleListContainer.addEventListener("click", async (e) => {
      if (e.target.closest(".forum-item-info")) {
        e.preventDefault();
        await this.showNewVersionPreview();
        return false;
      }
    });

    // 如果網址帶有 snA 參數
    if (window.location.href.includes("snA=")) {
      await this.showNewVersionPreview();
    }
  }

  /**
   * 顯示新版預覽
   */
  async showNewVersionPreview() {
    const previewBox = document.getElementById("article-content-box");
    const topBarCover = document.querySelector(".bee-top-bar-cover");

    previewBox.style.transform = "translateX(0%)";
    previewBox.style.width = this.settings.get("preview_size") || "80%";

    topBarCover.style.height = "100vh";
    topBarCover.style.opacity = "0.7";

    // 等待C頁面載入並添加AI功能
    await this.waitForCPageLoad();
  }

  /**
   * 等待C頁面載入
   */
  async waitForCPageLoad() {
    return new Promise((resolve) => {
      const observer = new MutationObserver(async (mutations) => {
        if (document.querySelectorAll(".c-section__main.c-post").length > 0) {
          observer.disconnect();
          // 移動快速回覆、板務工具
          let managertools = document.querySelector(".managertools");
          if (managertools) {
            managertools = document
              .querySelector(".article-content-box")
              .appendChild(managertools.parentElement);
          }
          const quickReply = document.querySelector(".c-editor.c-quick-reply");
          if (quickReply) {
            document
              .querySelector(".article-content-box")
              .appendChild(quickReply.parentElement);
          }
          // 添加額外功能
          if (this.settings.getBool("addSummaryBtn")) {
            const cPageWorker = new CPageWorker(this.settings);
            await cPageWorker.addPostButtons(this.isNewVersion);
            cPageWorker.addSkipFloorButton();
          }
          resolve();
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
    });
  }

  /**
   * 設置舊版預覽
   */
  setupOldVersionPreview() {
    this.handlePicModeAdjustment();
    this.setupOldVersionClickHandlers();
  }

  /**
   * 處理圖片模式調整
   */
  handlePicModeAdjustment() {
    const picMode = document.querySelectorAll(".imglist-text").length !== 0;

    if (picMode) {
      const switchTopics = document.querySelectorAll(".b-list__main");
      switchTopics.forEach((topic) => {
        const topicTexts = topic.childNodes[1].childNodes[3];
        if (topicTexts && topicTexts.className === "imglist-text") {
          topic.childNodes[1].removeChild(topicTexts);
          topic.insertAdjacentHTML("beforeend", topicTexts.outerHTML);
        }
      });
    }
  }

  /**
   * 設置舊版點擊處理器
   */
  setupOldVersionClickHandlers() {
    const picMode = document.querySelectorAll(".imglist-text").length !== 0;

    // 標題點擊
    const titleLinks = document.querySelectorAll(".b-list__main__title");
    titleLinks.forEach((link) => {
      link.addEventListener("click", (e) => {
        e.preventDefault();
        const href = link.getAttribute("href");
        this.openInFrame(`https://forum.gamer.com.tw/${href}`);
        return false;
      });
    });

    // 頁面點擊
    const pageSelector = picMode
      ? "#BH-master > form > div > table > tbody > tr > td.b-list__main > div > div > span > span"
      : "#BH-master > form > div > table > tbody > tr > td.b-list__main > span > a";

    const pageLinks = document.querySelectorAll(pageSelector);
    pageLinks.forEach((link) => {
      link.addEventListener("click", (e) => {
        e.preventDefault();
        const href = link.getAttribute(picMode ? "data-page" : "href");
        this.openInFrame(`https://forum.gamer.com.tw/${href}`);
        return false;
      });
    });
  }

  /**
   * 創建預覽框架
   */
  async createPreviewFrame() {
    const previewContainer = this.createPreviewContainer();
    const iframe = this.createIframe();

    previewContainer.appendChild(iframe);
    document.body.appendChild(previewContainer);

    this.previewFrame = iframe;
    await this.initializePreviewContainer(previewContainer);
    this.setupPreviewCloseHandler();
  }

  /**
   * 創建預覽容器
   */
  createPreviewContainer() {
    const container = document.createElement("div");
    container.className = "bee_preview_wd";

    Object.assign(container.style, {
      height: "100%",
      width: this.settings.get("preview_size"),
      transform: "scaleX(0)",
      zIndex: "100",
      position: "fixed",
      top: "0px",
      [this.settings.getBool("preview_LR") ? "right" : "left"]: "1%",
    });

    return container;
  }

  /**
   * 創建iframe
   */
  createIframe() {
    const iframe = document.createElement("iframe");
    iframe.id = "bee_frame";
    iframe.title = "bee_frame";
    iframe.src = "";

    Object.assign(iframe.style, {
      border: "0em solid rgb(170, 50, 220, 0)",
      width: "100%",
      height: "100%",
    });

    return iframe;
  }

  /**
   * 初始化預覽容器
   */
  async initializePreviewContainer(container) {
    const animationDirection = this.settings.getBool("preview_LR")
      ? "rl"
      : "lr";
    await this.popElementInit(container, false, animationDirection, false);
  }

  /**
   * 設置預覽關閉處理器
   */
  setupPreviewCloseHandler() {
    const menuPath = document.querySelector("#BH-menu-path");
    if (!menuPath) return;

    Object.assign(menuPath.style, {
      transition: "all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s",
      height: "40px",
      opacity: "1",
    });

    menuPath.addEventListener("click", () => {
      const container = document.querySelector(".bee_preview_wd");
      const direction = this.settings.getBool("preview_LR") ? "rl" : "lr";
      this.popElement(container, "false", direction);
      menuPath.style.height = "40px";
      menuPath.style.opacity = "1";
    });
  }

  /**
   * 在框架中打開URL
   */
  openInFrame(url) {
    if (!this.previewFrame) return;

    this.previewFrame.src = url;
    const menuPath = document.querySelector("#BH-menu-path");

    if (menuPath) {
      menuPath.style.height = "100%";
      menuPath.style.opacity = "0.6";
    }

    setTimeout(() => {
      const container = document.querySelector(".bee_preview_wd");
      const direction = this.settings.getBool("preview_LR") ? "rl" : "lr";
      this.popElement(container, "true", direction);
    }, 1000);

    // 設置iframe內的樣式
    setTimeout(() => {
      this.setupIframeStyles();
    }, 1000);
  }

  /**
   * 設置iframe內的樣式
   */
  setupIframeStyles() {
    try {
      const iframeDoc =
        this.previewFrame.contentDocument ||
        this.previewFrame.contentWindow.document;
      const styleSheet = iframeDoc.createElement("style");
      iframeDoc.head.appendChild(styleSheet);

      const sheet = styleSheet.sheet;
      sheet.insertRule(
        ".managertools { position: fixed; bottom: 0; right: 0; z-index: 100; }",
        0
      );
    } catch (error) {
      console.warn("無法設置iframe樣式:", error);
    }
  }

  /**
   * 初始化版面佈局
   */
  initializeLayout() {
    if (this.isNewVersion) {
      this.setupNewVersionLayout();
    } else {
      this.setupOldVersionLayout();
    }
  }

  /**
   * 設置新版版面
   */
  setupNewVersionLayout() {
    if (this.settings.getBool("cleanMode")) {
      this.enableCleanMode();
    }

    this.setupSlaveDisplay();
    this.setupOrderSwitching();
  }

  /**
   * 啟用清爽模式
   */
  enableCleanMode() {
    if (document.getElementById("cleanModeStyles")) {
      return;
    }
    const style = document.createElement("style");
    style.id = "cleanModeStyles";
    style.textContent = `
    /* 移除描述和縮圖 */
    .forum-item-desc,
    .forum-item-thumbnail {
      display: none !important;
    }
 
    /* 調整列表項目樣式 */
    .forum-list-item {
      padding: 0 !important;
      min-height: ${this.settings.get("cleanModeSize")} !important; 
    }
  `;
    document.head.appendChild(style);
  }

  /**
   * 設置從屬顯示
   */
  setupSlaveDisplay() {
    if (document.getElementById("showSlave")) {
      return;
    }
    const style = document.createElement("style");
    style.id = "showSlave";
    style.textContent = `
    #BH-slave {
      display: block !important;
    }
  `;
    document.head.appendChild(style);
  }

  /**
   * 設置順序切換
   */
  setupOrderSwitching() {
    if (document.getElementById("orderSwitching")) {
      return;
    }
    const style = document.createElement("style");
    style.id = "orderSwitching";
    style.textContent = `
    #BH-master {
      order: 2 !important;
    }
    #BH-slave {
      order: 1 !important;
      margin-left: 0 !important;
      margin-right: 12px !important;
    }
  `;
    document.head.appendChild(style);
  }

  /**
   * 設置舊版版面
   */
  setupOldVersionLayout() {
    if (this.settings.getBool("new_design_LRSwitch")) {
      const master = document.getElementById("BH-master");
      const slave = document.getElementById("BH-slave");

      if (master && slave) {
        master.style.float = "right";
        slave.style.float = "left";
      }
    }
  }

  /**
   * 初始化交互功能
   */
  initializeInteractions() {
    this.setupCheckboxSystem();
    this.setupBorderInPicMode();
  }

  /**
   * 設置複選框系統
   */
  setupCheckboxSystem() {
    const titleElements = this.getTitleElements();
    const checkboxes = this.getCheckboxElements();

    titleElements.forEach((title, index) => {
      this.setupTitleClickHandler(title, checkboxes, index);
    });
  }

  /**
   * 獲取標題元素
   */
  getTitleElements() {
    const hasImgList = document.querySelectorAll(".imglist-text").length > 0;
    return hasImgList
      ? document.getElementsByClassName("b-list__main")
      : document.getElementsByClassName("b-list__main");
  }

  /**
   * 獲取複選框元素
   */
  getCheckboxElements() {
    try {
      return document.getElementsByName("jsn[]");
    } catch (error) {
      return [];
    }
  }

  /**
   * 設置標題點擊處理器
   */
  setupTitleClickHandler(title, checkboxes, index) {
    // 防止子元素觸發
    const children = title.querySelectorAll("*");
    children.forEach((child) => {
      child.addEventListener("click", (event) => {
        event.stopPropagation();
      });
    });

    // 重置複選框
    if (checkboxes[index]) {
      checkboxes[index].checked = false;
    }

    title.onclick = (e) => {
      this.handleTitleClick(title, checkboxes, e);
    };
  }

  /**
   * 處理標題點擊
   */
  handleTitleClick(title, checkboxes, event) {
    const hasValidContent =
      title.querySelector(".b-list__main__title") ||
      title.querySelector(".imglist-text");

    if (!hasValidContent) return;

    // 隱藏管理器
    const manager = document.querySelector(".bee_manager");
    if (manager) {
      manager.style.display = "none";
    }

    // 處理複選框邏輯
    const snA = this.extractSnA(title.innerHTML);
    if (!snA) return;

    let hasCheckedBox = false;
    checkboxes.forEach((checkbox) => {
      if (checkbox.value === snA) {
        checkbox.checked = !checkbox.checked;
        title.style.backgroundColor = checkbox.checked
          ? this.settings.get("bee_select_color")
          : "";

        if (checkbox.checked) {
          hasCheckedBox = true;
        }
      }
    });

    // 顯示管理器
    if (hasCheckedBox && manager) {
      this.showManagerAtCursor(manager, event);
    }
  }

  /**
   * 提取snA值
   */
  extractSnA(innerHTML) {
    const match = innerHTML.match(/snA=(\d*)/);
    return match ? match[1] : null;
  }

  /**
   * 在游標位置顯示管理器
   */
  showManagerAtCursor(manager, event) {
    manager.style.left = `${event.clientX + 50}px`;
    manager.style.top = `${event.clientY - 170}px`;
    manager.style.display = "block";
  }

  /**
   * 設置圖片模式邊框
   */
  setupBorderInPicMode() {
    if (!this.settings.getBool("addBorderInPicMode")) return;

    const picModeBlocks = document.querySelectorAll(
      "#BH-master > form > div > table > tbody > tr > td.b-list__main > div > p"
    );

    picModeBlocks.forEach((block) => {
      block.style.borderTop = "dashed";
    });
  }

  /**
   * 初始化選單
   */
  initializeMenu() {
    if (this.isNewVersion) return;

    this.createManagerMenu();
    this.setupLinkClickPrevention();
  }

  /**
   * 創建管理器選單
   */
  createManagerMenu() {
    try {
      const managertools = document.querySelector(".managertools");
      if (!managertools) return;

      const bManagerDiv = this.createManagerContainer();
      const buttonGroups = this.createButtonGroups(managertools);

      bManagerDiv.appendChild(this.createCheckboxContainer());
      buttonGroups.forEach((group) => bManagerDiv.appendChild(group));

      managertools.parentElement.appendChild(bManagerDiv);
    } catch (error) {
      console.warn("創建管理器選單失敗:", error);
    }
  }

  /**
   * 創建管理器容器
   */
  createManagerContainer() {
    const container = document.createElement("div");
    container.className = "b-manager managertools bee_manager";

    Object.assign(container.style, {
      zIndex: "100",
      position: "fixed",
      width: "auto",
    });

    return container;
  }

  /**
   * 創建複選框容器
   */
  createCheckboxContainer() {
    const checkboxDiv = document.createElement("div");
    checkboxDiv.className = "checkbox";

    const label = document.createElement("label");
    label.setAttribute("for", "check");

    checkboxDiv.appendChild(label);
    return checkboxDiv;
  }

  /**
   * 創建按鈕組
   */
  createButtonGroups(managertools) {
    const buttonIndexes = [
      [0, 3, 7],
      [2, 4],
      [1, 8],
      [5, 6],
    ];

    return buttonIndexes.map((indexes) => {
      const beeDiv = document.createElement("div");
      beeDiv.className = "bee";
      beeDiv.style.padding = "5px";

      indexes.forEach((index) => {
        const buttons = managertools.querySelectorAll("button");
        if (buttons[index]) {
          const button = buttons[index].cloneNode(true);
          beeDiv.appendChild(button);
        }
      });

      return beeDiv;
    });
  }

  /**
   * 設置連結點擊防止
   */
  setupLinkClickPrevention() {
    const selectors = [
      "#BH-master > form > div > table > tbody > tr > td.b-list__main > a",
      "#BH-master > form > div > table > tbody > tr > td.b-list__main",
    ];

    selectors.forEach((selector) => {
      const elements = document.querySelectorAll(selector);
      elements.forEach((element) => {
        element.addEventListener("click", (event) => {
          event.stopPropagation();
        });
      });
    });
  }

  /**
   * 初始化設計
   */
  initializeDesign() {
    if (!this.settings.getBool("new_design")) return;

    this.applyNewDesign();
  }

  /**
   * 應用新設計
   */
  applyNewDesign() {
    if (document.getElementById("newDesignStyles")) {
      return;
    }
    const style = document.createElement("style");
    style.id = "newDesignStyles";
    style.textContent = `
    #BH-slave {
      width: ${this.settings.get("new_design_box_Right")} !important;
      max-width: 100vw !important;
    }
    #BH-master {
      width: ${this.settings.get("new_design_box_Left")} !important;
    }
  `;
    document.head.appendChild(style);

    if (this.isNewVersion) {
      this.applyNewVersionDesign();
    } else {
      this.applyOldVersionDesign();
    }
  }

  /**
   * 應用新版設計
   */
  applyNewVersionDesign() {
    if (document.getElementById("newVersionStyles")) {
      return;
    }
    const style = document.createElement("style");
    style.id = "newVersionStyles";
    const slaveStyleCss = this.settings.getBool("new_design_LRSwitch")
      ? "left: 0% !important;"
      : "right: 0% !important;";
    const adPositionCss = this.settings.getBool("new_design_LRSwitch")
      ? "right: 0;"
      : "left: 0;";
    const showFixedRightAtLeft = this.settings.getBool("new_design_LRSwitch")
      ? ""
      : "left: 300px !important; right: unset !important;";
    style.textContent = `
    #forum-list-box {
      left: 50% !important;
      transform: translateX(-50%) !important;
    }
    .forum-box.split .forum-list-box {
      width: ${this.settings.get("new_design_box")} !important;
    }
    #BH-slave {
      position: fixed !important;
      bottom: 0% !important;
      z-index: 100 !important;
      ${slaveStyleCss}
    }
    #buildingAdB {
      position: absolute !important;
      bottom: 0 !important;
      ${adPositionCss}
    }
    .fixed-right {
      ${showFixedRightAtLeft}
    }
  `;
    document.head.appendChild(style);

    const changeAdPosition = document.getElementById("buildingAdB");
    const mainBox = document.querySelector(".forum-main");
    mainBox.prepend(changeAdPosition);
  }

  /**
   * 應用舊版設計
   */
  applyOldVersionDesign() {
    const wrapper = document.getElementById("BH-wrapper");
    if (wrapper) {
      wrapper.style.width = this.settings.get("new_design_box");
    }
  }

  /**
   * 初始化功能
   */
  initializeFunctions() {
    if (!this.settings.getBool("add_function") || this.isNewVersion) return;

    this.addFunctionButtons();
  }

  /**
   * 添加功能按鈕
   */
  addFunctionButtons() {
    const titleElements = document.getElementsByClassName("b-list__main");
    const titleLinks = document.getElementsByClassName("b-list__main__title");

    // 創建新的td元素
    const newTd = document.createElement("td");
    const filterElement = document.querySelector(".b-list__filter");
    if (filterElement) {
      filterElement.insertAdjacentElement("afterend", newTd);
    }

    // 為每個標題添加功能按鈕
    Array.from(titleElements).forEach((title, index) => {
      if (titleLinks[index]) {
        const buttonContainer = this.createFunctionButtonContainer(
          titleLinks[index]
        );
        title.insertAdjacentElement("afterend", buttonContainer);
      }
    });

    this.setupFunctionButtonHover();
  }

  /**
   * 創建功能按鈕容器
   */
  createFunctionButtonContainer(titleLink) {
    const td = document.createElement("td");
    td.style.width = "auto";

    const hrefValue = titleLink.getAttribute("href");
    const isDarkTheme = this.checkDarkTheme();

    const buttons = this.createFunctionButtons(hrefValue, isDarkTheme);
    buttons.forEach((button) => td.appendChild(button));

    return td;
  }

  /**
   * 檢查是否為暗色主題
   */
  checkDarkTheme() {
    const menuPath = document.getElementById("BH-menu-path");
    if (!menuPath) return false;

    const bgColor = window.getComputedStyle(menuPath).backgroundColor;
    return bgColor === "rgb(28, 28, 28)";
  }

  /**
   * 創建功能按鈕
   */
  createFunctionButtons(hrefValue, isDarkTheme) {
    const buttonConfigs = [
      {
        title: "快速瀏覽",
        class: "bee_preview",
        icon: "fullscreen",
        onclick: () =>
          this.openInFrame("https://forum.gamer.com.tw/" + hrefValue),
      },
      {
        title: "開新視窗",
        class: "bee_open_new_wd",
        icon: "open_in_new",
        onclick: () => window.open(hrefValue),
      },
      {
        title: "複製連結",
        class: "bee_link",
        icon: "link",
        onclick: () =>
          navigator.clipboard.writeText(
            "https://forum.gamer.com.tw/" + hrefValue
          ),
      },
    ];

    return buttonConfigs.map((config) => {
      const button = document.createElement("a");
      button.title = config.title;
      button.className = `btn-icon btn-icon--inverse ${config.class}`;
      button.style.display = "none";
      button.onclick = config.onclick;

      const icon = document.createElement("i");
      icon.className = `material-icons ${config.class}`;
      icon.textContent = config.icon;

      if (!isDarkTheme) {
        icon.style.color = "rgba(0, 0, 0, 0.4)";
      }

      button.appendChild(icon);
      return button;
    });
  }

  /**
   * 設置功能按鈕懸停效果
   */
  setupFunctionButtonHover() {
    const rows = document.querySelectorAll(".b-list__row");

    rows.forEach((row) => {
      row.addEventListener("mouseover", () => {
        this.toggleFunctionButtons(row, true);
      });

      row.addEventListener("mouseout", () => {
        this.toggleFunctionButtons(row, false);
      });
    });
  }

  /**
   * 切換功能按鈕顯示
   */
  toggleFunctionButtons(row, show) {
    const buttonClasses = [".bee_preview", ".bee_open_new_wd", ".bee_link"];

    buttonClasses.forEach((className) => {
      const button = row.querySelector(className);
      if (button) {
        button.style.display = show ? "" : "none";
      }
    });
  }

  /**
   * 初始化樣式
   */
  initializeStyles() {
    // 樣式相關的初始化可以在這裡添加
  }

  /**
   * 彈出元素初始化
   */
  async popElementInit(element, show = true, anime = "ud", waitAppend = true) {
    if (waitAppend) {
      requestAnimationFrame(() => {
        this.setElementDimensions(element);
      });
    } else {
      this.setElementDimensions(element);
    }

    this.setupElementTransition(element, show, anime);
  }

  /**
   * 設置元素尺寸
   */
  setElementDimensions(element) {
    element.style.readHeight =
      element.scrollHeight === 0 ? "999px" : `${element.scrollHeight}px`;
    element.style.readWidth =
      element.scrollWidth === 0 ? "999px" : `${element.scrollWidth}px`;
  }

  /**
   * 設置元素過渡
   */
  setupElementTransition(element, show, anime) {
    Object.assign(element.style, {
      transition: "",
      overflow: "hidden auto",
      opacity: "0",
    });

    this.popElement(element, "false", anime);
    element.style.transition =
      "all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s";

    if (!show) {
      element.style.beeShow = "false";
      return;
    }

    element.style.beeShow = "true";
    element.style.opacity = "1";

    requestAnimationFrame(() => {
      element.style.maxHeight = element.style.readHeight;
    });
  }

  /**
   * 彈出元素控制
   */
  popElement(element, show = "true", anime = "ud") {
    const doShow =
      show === "toggle" ? !(element.style.beeShow === "true") : show === "true";

    if (doShow) {
      this.showElement(element);
    } else {
      this.hideElement(element, anime);
    }
  }

  /**
   * 顯示元素
   */
  showElement(element) {
    Object.assign(element.style, {
      opacity: "1",
      maxHeight: element.style.readHeight,
      maxWidth: element.style.readWidth,
      transform: "translateX(0px) translateY(0px)",
      beeShow: "true",
    });
  }

  /**
   * 隱藏元素
   */
  hideElement(element, anime) {
    element.style.beeShow = "false";
    element.style.opacity = "0";

    if (anime.includes("u")) {
      element.style.maxHeight = "0px";
      if (anime.startsWith("d")) {
        element.style.transform = `translateX(0px) translateY(${element.style.readWidth}px)`;
      }
    }

    if (anime.includes("l")) {
      element.style.maxWidth = "0px";
      if (anime.startsWith("r")) {
        element.style.transform = `translateX(${element.style.readHeight}) translateY(0px)`;
      }
    }
  }
}
/**
 * C頁面工作模組
 * 負責C頁面的AI功能,包括懶人包、留言統整、問問功能等
 */
class CPageWorker {
  constructor(settings) {
    this.settings = settings;
    this.gptRequestQueue = [];
    this.isProcessingQueue = false;
  }

  /**
   * 初始化C頁面功能
   */
  async init() {
    if (!this.isCPage()) return;

    this.setupCPageStyles();

    if (this.settings.getBool("addSummaryBtn")) {
      await this.addPostButtons();
    }
  }

  /**
   * 檢查是否為C頁面
   */
  isCPage() {
    return window.location.href.includes("forum.gamer.com.tw/C.php");
  }

  /**
   * 設置C頁面樣式
   */
  setupCPageStyles() {
    const styleSheet = document.createElement("style");
    document.head.appendChild(styleSheet);
    const sheet = styleSheet.sheet;

    sheet.insertRule(
      ".managertools { position: fixed; bottom: 0; right: 0; z-index: 100; }",
      0
    );
  }

  /**
   * 添加文章按鈕
   */
  async addPostButtons(isNewVersion = false) {
    await this.updatePrompts();

    const postSections = this.getPostSections();
    postSections.forEach((postSection) => {
      if (this.hasEditPermission(postSection)) return;
      this.addAskButton(postSection);
      const summaryButton = this.addSummaryButton(postSection);
      this.addCommentSummaryButton(postSection);

      // 可選功能(目前註解)
      // this.addSkipFloorButton(postSections, postSection);
      // this.addSummaryButtonLeft(postSection, summaryButton);
    });
  }

  /**
   * 獲取文章區塊
   */
  getPostSections() {
    return Array.from(document.querySelectorAll(".c-section")).filter(
      (section) => section.querySelector(".c-post__body")
    );
  }

  /**
   * 檢查是否已經新增按鈕
   */
  hasEditPermission(postSection) {
    const editIcon = postSection.querySelectorAll(".lazyBtn");
    return editIcon !== null && editIcon.length > 0;
  }

  /**
   * 添加懶人包按鈕
   */
  addSummaryButton(postSection) {
    const postBody = postSection.querySelector(".c-post__body");
    const footerRight = postBody.querySelector(".article-footer_right");

    const summaryButton = this.createButton({
      text: "懶人包",
      icon: "description",
      id: `lazy-summary-${postBody.querySelector(".c-article").id}`,
      insertPosition: "first",
    });

    footerRight.insertBefore(summaryButton, footerRight.firstChild);

    summaryButton.addEventListener("click", async () => {
      await this.handleSummaryClick(summaryButton, postBody);
    });

    return summaryButton;
  }
  /**
   * 添加跳過樓層 - 按需檢測版本
   */
  addSkipFloorButton() {
    //檢查按鈕是否已經存在
    if (document.getElementById("floating-skip-button")) {
      // remove
      document.getElementById("floating-skip-button").remove();
    }
    // 創建右側浮動的跳過按鈕
    const floatingSkipButton = this.createFloatingSkipButton();
    document.body.appendChild(floatingSkipButton);

    // 點擊事件處理 - 只在點擊時檢查當前樓層
    floatingSkipButton.addEventListener("click", () => {
      const cPageWorker = new CPageWorker(this.settings);
      const postSections = cPageWorker.getPostSections();
      const currentSection = this.findCurrentVisibleSection(postSections);

      if (currentSection) {
        const currentIndex = Array.from(postSections).indexOf(currentSection);
        const nextSection = postSections[currentIndex + 1];

        if (nextSection) {
          // 暫時禁止點擊
          floatingSkipButton.disabled = true;
          this.scrollToElement(nextSection, 2);
          // 700毫秒後恢復
          setTimeout(() => {
            floatingSkipButton.disabled = false;
          }, 700);
          this.animateButtonClick(floatingSkipButton);
        } else {
          // 已到最後一樓
          this.handleLastFloor(currentSection, floatingSkipButton);
        }
      }
    });
  }
  /**
   * 創建浮動跳過按鈕
   */
  createFloatingSkipButton() {
    const button = document.createElement("button");
    button.id = "floating-skip-button";
    button.innerHTML = `
      <i class="fa fa-arrow-down"></i>
      <span>跳過此樓</span>
    `;
    // 添加CSS動畫到頁面
    if (!document.getElementById("arrow-bounce-style")) {
      const style = document.createElement("style");
      style.id = "arrow-bounce-style";
      style.textContent = `
        @keyframes arrowBounce {
          0%, 100% { transform: translateY(0); }
          25% { transform: translateY(-3px); }
          50% { transform: translateY(2px); }
          75% { transform: translateY(-1px); }
        }
      `;
      document.head.appendChild(style);
    }

    // 設置按鈕樣式
    Object.assign(button.style, {
      position: "fixed",
      right: "20px",
      bottom: "300px",
      transform: "translateY(-50%)",
      zIndex: "9999",
      backgroundColor: "var(--primary)",
      color: "var(--primary-text)",
      border: "none",
      borderRadius: "50px",
      padding: "12px 16px",
      cursor: "pointer",
      boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
      display: "flex",
      alignItems: "center",
      gap: "8px",
      fontSize: "14px",
      fontWeight: "500",
      transition: "all 0.3s ease",
      opacity: "0.8",
    });

    // 懸停效果 - 帶箭頭跳動動畫
    button.addEventListener("mouseenter", () => {
      // 為箭頭添加跳動動畫
      const arrow = button.querySelector("i");
      if (arrow) {
        arrow.style.animation = "arrowBounce 0.6s ease-in-out";
      }
    });

    button.addEventListener("mouseleave", () => {
      // 移除箭頭動畫
      const arrow = button.querySelector("i");
      if (arrow) {
        arrow.style.animation = "";
      }
    });

    return button;
  }
  /**
   * 找出當前在視野中的樓層
   */
  findCurrentVisibleSection(postSections) {
    // 使用你現有的 isElementInViewport 函式
    for (let i = 0; i < postSections.length; i++) {
      const section = postSections[i];
      if (UtilityFunctions.isInViewport(section)) {
        return section;
      }
    }

    // 如果沒有找到完全可見的,找最接近視窗頂部的
    return this.findClosestSection(postSections);
  }

  /**
   * 找出最接近視窗頂部的樓層(備用方案)
   */
  findClosestSection(postSections) {
    let closestSection = null;
    let minDistance = Infinity;

    postSections.forEach((section) => {
      const rect = section.getBoundingClientRect();
      const distance = Math.abs(rect.top);

      if (distance < minDistance) {
        minDistance = distance;
        closestSection = section;
      }
    });

    return closestSection;
  }
  /**
   * 按鈕點擊動畫效果
   */
  animateButtonClick(button) {
    button.style.transform = "translateY(-50%) scale(0.95)";
    setTimeout(() => {
      button.style.transform = "translateY(-50%) scale(1)";
    }, 150);
  }
  /**
   * 處理到達最後一樓的情況
   */
  handleLastFloor(lastSection, button) {
    const footer = lastSection.querySelector(".c-post__footer");

    if (footer) {
      // 滾動到 footer 元素
      this.scrollToElement(footer);
      this.animateButtonClick(button);

      // 更新按鈕狀態
      button.style.opacity = "0.6";
      button.innerHTML = `
      <i class="fa fa-anchor"></i>
      <span>已到樓底</span>
    `;

      // 3秒後恢復按鈕狀態
      setTimeout(() => {
        button.style.opacity = "0.8";
        button.innerHTML = `
        <i class="fa fa-arrow-down"></i>
        <span>跳過此樓</span>
      `;
      }, 3000);
    } else {
      // 如果找不到 footer,就滾動到樓層底部
      this.handleLastFloorFallback(lastSection, button);
    }
  }
  /**
   * 處理找不到 footer 的備用方案
   */
  handleLastFloorFallback(lastSection, button) {
    // 滾動到樓層元素的底部
    const elementBottom = lastSection.offsetTop + lastSection.offsetHeight;
    window.scrollTo({
      top: elementBottom - window.innerHeight + 100, // 留一點邊距
      behavior: "smooth",
    });

    this.animateButtonClick(button);

    // 更新按鈕狀態
    button.style.opacity = "0.5";
    button.innerHTML = `
      <i class="fa fa-check"></i>
      <span>已到底部</span>
    `;

    // 3秒後恢復按鈕狀態
    setTimeout(() => {
      button.style.opacity = "0.8";
      button.innerHTML = `
        <i class="fa fa-arrow-down"></i>
        <span>跳過此樓</span>
      `;
    }, 3000);
  }

  /**
   * 處理懶人包按鈕點擊
   */
  async handleSummaryClick(button, postBody) {
    this.scrollToElement(button);

    if (button.querySelector("p").textContent === "產生中...") return;

    if (!this.validateApiKey()) return;

    const articleId = postBody.querySelector(".c-article").id;
    const cleanId = `${articleId}-clean`;

    // 處理展開/摺疊邏輯
    if (this.handleToggleLogic(button, cleanId)) return;

    // 生成懶人包
    await this.generateSummary(button, postBody, articleId);
  }

  /**
   * 生成懶人包
   */
  async generateSummary(button, postBody, articleId) {
    button.querySelector("p").textContent = "產生中...";

    const articleContent = this.extractArticleContent(postBody);
    const customPrompt = this.settings.get("custom_oaiPrompt");
    const prompt = customPrompt || this.settings.get("oaiPrompt");

    const { response, data } = await this.sendGptRequest(
      prompt,
      `文章內容:\`\`\`${articleContent}\`\`\``
    );

    if (!response) {
      button.querySelector("p").textContent = "懶人包";
      return;
    }

    const summaryArticle = this.createSummaryArticle(
      `${articleId}-clean`,
      data.choices[0].message.content
    );

    button.querySelector("p").textContent = "摺疊 ▲";
    postBody.appendChild(summaryArticle);

    await this.animateElement(summaryArticle, true);
  }

  /**
   * 添加留言統整按鈕
   */
  addCommentSummaryButton(postSection) {
    const postBody = postSection.querySelector(".c-post__body");
    const replyHead = postSection.querySelector(".c-reply__head");

    if (!replyHead) return;

    const commentButton = this.createButton({
      text: "留言統整",
      icon: "forum",
      id: `lazy-summaryCmd-${postBody.querySelector(".c-article").id}`,
      className: "article-footer_right-btn",
      style: { margin: "0.3rem 0.5rem 0rem 0rem" },
    });

    replyHead.appendChild(commentButton);

    commentButton.addEventListener("click", async () => {
      await this.handleCommentSummaryClick(
        commentButton,
        postBody,
        postSection
      );
    });
  }

  /**
   * 處理留言統整按鈕點擊
   */
  async handleCommentSummaryClick(button, postBody, postSection) {
    this.scrollToElement(button);

    if (button.querySelector("p").textContent === "產生中...") return;

    if (!this.validateApiKey()) return;

    const postId = postBody.querySelector(".c-article").id.replace("cf", "");
    const cleanCmdId = `${postId}-cleanCmd`;

    // 處理展開/摺疊邏輯
    if (this.handleToggleLogic(button, cleanCmdId, "留言統整")) return;

    // 生成留言統整
    await this.generateCommentSummary(button, postId, postSection);
  }

  /**
   * 生成留言統整
   */
  async generateCommentSummary(button, postId, postSection) {
    button.querySelector("p").textContent = "產生中...";

    const commentData = await this.getCommentData(postId);
    const customPrompt = this.settings.get("custom_oaiPromptCmd");
    const prompt = customPrompt || this.settings.get("oaiPromptCmd");

    const { response, data } = await this.sendGptRequest(
      prompt,
      `對話內容:\n \`\`\`${commentData.textContent}\n\`\`\``
    );

    if (!response) {
      button.querySelector("p").textContent = "留言統整";
      return;
    }

    const processedContent = this.restoreOriginalFormat(
      data.choices[0].message.content,
      commentData.textContentOrigin
    );

    const summaryArticle = this.createCommentSummaryArticle(
      `${postId}-cleanCmd`,
      processedContent
    );

    button.querySelector("p").textContent = "摺疊 ▲";

    const insertBefore = document.getElementById(`Commendlist_${postId}`);
    postSection
      .querySelector(".c-post__footer")
      .insertBefore(summaryArticle, insertBefore);

    await this.animateElement(summaryArticle, true);
  }

  /**
   * 添加問問按鈕
   */
  addAskButton(postSection) {
    const postBody = postSection.querySelector(".c-post__body");
    const footerRight = postBody.querySelector(".article-footer_right");

    // 創建對話輸入區
    const { askInput, chatArea, askTextarea } =
      this.createChatInterface(postBody);

    // 創建問問按鈕
    const askButton = this.createButton({
      text: "問問 ▼",
      icon: "chat",
      id: `ask-${postBody.querySelector(".c-article").id}`,
      insertPosition: "first",
    });

    footerRight.insertBefore(askButton, footerRight.firstChild);

    // 設置事件監聽器
    this.setupAskButtonEvents(
      askButton,
      askInput,
      chatArea,
      askTextarea,
      postBody
    );
  }

  /**
   * 創建聊天介面
   */
  createChatInterface(postBody) {
    // 創建輸入區
    const askInput = document.createElement("div");
    askInput.classList.add("c-reply__editor");

    const replyInput = document.createElement("div");
    replyInput.classList.add("reply-input");

    const askTextarea = document.createElement("textarea");
    askTextarea.classList.add("content-edit");
    askTextarea.placeholder = "詢問⋯";

    replyInput.appendChild(askTextarea);
    askInput.appendChild(replyInput);
    postBody.appendChild(askInput);

    this.animateElement(askInput, false);

    // 創建聊天區域
    const chatArea = document.createElement("div");
    chatArea.classList.add("chatArea");
    chatArea.style.overflow = "hidden";

    postBody.insertBefore(chatArea, askInput);
    this.animateElement(chatArea, false);

    return { askInput, chatArea, askTextarea };
  }

  /**
   * 設置問問按鈕事件
   */
  setupAskButtonEvents(askButton, askInput, chatArea, askTextarea, postBody) {
    // 按鈕點擊事件
    askButton.addEventListener("click", async () => {
      this.scrollToElement(askButton);

      if (!this.validateApiKey()) return;

      const isExpanded = askButton.querySelector("p").textContent === "問問 ▲";

      this.toggleElement(askInput);
      this.toggleElement(chatArea);

      askButton.querySelector("p").textContent = isExpanded
        ? "問問 ▼"
        : "問問 ▲";

      if (!isExpanded) {
        askTextarea.focus();
      }
    });

    // 輸入框按鍵事件
    askTextarea.addEventListener("keydown", async (e) => {
      if (e.key === "Enter" && !e.shiftKey) {
        e.preventDefault();
        await this.handleAskQuestion(askTextarea, chatArea, postBody);
      }
    });
  }

  /**
   * 處理問問功能
   */
  async handleAskQuestion(askTextarea, chatArea, postBody) {
    if (!this.validateApiKey()) return;
    if (askTextarea.placeholder !== "詢問⋯") return;

    const userInput = askTextarea.value;
    if (!userInput.trim()) return;

    askTextarea.placeholder = "載入中⋯";
    askTextarea.value = "";

    const gptArray = this.buildChatGptArray(postBody, chatArea, userInput);

    const { response, data } = await this.sendGptArrayRequest(gptArray);

    if (!response) {
      askTextarea.placeholder = "詢問⋯";
      askTextarea.value = userInput;
      return;
    }

    // 添加用戶問題
    this.addChatMessage(chatArea, userInput, "user-ask");

    // 添加AI回答
    this.addChatMessage(chatArea, data.choices[0].message.content, "gpt-reply");

    // 更新聊天區域高度
    this.updateChatAreaHeight(chatArea);

    askTextarea.placeholder = "詢問⋯";
    askTextarea.focus();
  }

  /**
   * 構建聊天GPT陣列
   */
  buildChatGptArray(postBody, chatArea, userInput) {
    const gptArray = [];
    const customPrompt = this.settings.get("custom_oaiPromptChat");
    const prompt = customPrompt || this.settings.get("oaiPromptChat");
    const useSystemMode = this.settings.getBool("oaiPromptSystemMode");

    // 添加系統提示
    gptArray.push({
      role: useSystemMode ? "system" : "user",
      content: prompt,
    });

    if (!useSystemMode) {
      gptArray.push({
        role: "assistant",
        content: "好的,請提供文章。",
      });
    }

    // 添加文章內容
    const articleContent = this.extractArticleContent(postBody);
    gptArray.push({
      role: "user",
      content: `文章內容:\n\`\`\`\n${articleContent}\n\`\`\``,
    });

    // 添加聊天歷史
    const chatHistory = chatArea.querySelectorAll(".chatHistory");
    chatHistory.forEach((chat) => {
      const role = chat.classList.contains("user-ask") ? "user" : "assistant";
      const content = chat.querySelector(".c-article__content").textContent;
      gptArray.push({ role, content });
    });

    // 添加當前問題
    gptArray.push({
      role: "user",
      content: userInput,
    });

    return gptArray;
  }

  /**
   * 添加聊天訊息
   */
  addChatMessage(chatArea, content, type) {
    const messageArticle = document.createElement("article");
    messageArticle.classList.add("c-article", "FM-P2", "chatHistory", type);
    messageArticle.id = `chat-${Date.now()}-${Math.random()
      .toString(36)
      .substr(2, 9)}`;

    Object.assign(messageArticle.style, {
      display: "block",
      minHeight: "0px",
      marginBottom: type === "user-ask" ? "0.8rem" : "1.6rem",
      borderBottom: `1px solid ${
        type === "user-ask" ? "var(--primary-text)" : "var(--primary)"
      }`,
    });

    const messageContent = document.createElement("div");
    messageContent.classList.add("c-article__content");
    messageContent.style.whiteSpace = "pre-wrap";
    messageContent.innerHTML = content;

    messageArticle.appendChild(messageContent);
    chatArea.appendChild(messageArticle);
  }

  /**
   * 更新聊天區域高度
   */
  updateChatAreaHeight(chatArea) {
    requestAnimationFrame(() => {
      chatArea.style.readHeight = `${chatArea.scrollHeight}px`;
      chatArea.style.maxHeight = `${chatArea.scrollHeight}px`;
    });
  }

  /**
   * 獲取留言資料
   */
  async getCommentData(postId) {
    let commentElements = document
      .getElementById(`Commendlist_${postId}`)
      .querySelectorAll(".c-reply__item");

    // 展開留言
    const showButton = document.getElementById(`showoldCommend_${postId}`);
    if (
      showButton &&
      (showButton.style.display === "block" || showButton.style.display === "")
    ) {
      const initialCount = commentElements.length;
      showButton.click();

      await new Promise((resolve) => {
        const observer = new MutationObserver(() => {
          const currentElements = document
            .getElementById(`Commendlist_${postId}`)
            .querySelectorAll(".c-reply__item");

          if (currentElements.length >= initialCount) {
            commentElements = currentElements;
            document.getElementById(`closeCommend_${postId}`).click();
            observer.disconnect();
            resolve();
          }
        });

        observer.observe(document.getElementById(`Commendlist_${postId}`), {
          childList: true,
          subtree: true,
          characterData: true,
        });
      });

      document.getElementById(`closeCommend_${postId}`).click();
    }

    // 處理留言內容
    let textContent = "";
    const textContentOrigin = Array.from(commentElements)
      .map((node) => node.innerHTML)
      .join("");

    commentElements.forEach((node) => {
      const user = node.querySelector(".reply-content__user").innerHTML;
      const comment = node.querySelector(".comment_content").innerHTML;
      textContent += `@${user}:${comment}\n`;
    });

    // 清理格式
    textContent = textContent.replace(/\n+/g, "\n");
    textContent = this.processCommentReferences(textContent);

    return { textContent, textContentOrigin };
  }

  /**
   * 處理留言引用格式
   */
  processCommentReferences(textContent) {
    const patterns = [
      {
        regex: /([^<]+)\((.*?)\)<\/a>/g,
        replacement: (match, prefix, name) => `回應@${name} => `,
      },
      {
        regex: /([^<]+)<\/a>/g,
        replacement: (match, name) => `回應@${name},`,
      },
    ];

    patterns.forEach(({ regex, replacement }) => {
      textContent = textContent.replace(regex, replacement);
    });

    return textContent;
  }

  /**
   * 還原原始格式
   */
  restoreOriginalFormat(textContent, originalContent) {
    const nameToHtmlMap = new Map();
    const htmlPattern = /([^<]+)<\/a>/g;
    let match;

    while ((match = htmlPattern.exec(originalContent)) !== null) {
      nameToHtmlMap.set(match[1], match[0]);
    }

    let processedText = textContent;
    nameToHtmlMap.forEach((html, name) => {
      const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
      const atPattern = new RegExp(`@${escapedName}`, "g");
      processedText = processedText.replace(atPattern, html);
    });

    return processedText;
  }

  /**
   * 更新提示詞
   */
  async updatePrompts() {
    const today = new Date();
    const lastUpdate = this.settings.get("oaiPromptUpdateDate");
    const sleepDays = parseInt(this.settings.get("oaiPromptUpdateSleep"));

    const daysDiff = Math.floor(
      (today -
        new Date(lastUpdate.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3"))) /
        (1000 * 60 * 60 * 24)
    );

    if (daysDiff < sleepDays) return;

    try {
      const response = await fetch(this.settings.get("oaiPromptUpdateURL"));
      if (!response.ok) {
        console.error("[ERROR] fetching prompt:", response.status);
        return;
      }

      const data = await response.json();
      const todayString = today.toISOString().slice(0, 10).replace(/-/g, "");

      this.settings.set("oaiPromptUpdateDate", todayString);

      if (this.settings.get("oaiPromptDate") >= data.oaiPromptDate) return;

      // 更新提示詞
      this.settings.set("oaiPromptDate", data.oaiPromptDate);
      this.settings.set("oaiPrompt", data.oaiPrompt);
      this.settings.set("oaiPromptUpdateSleep", data.oaiPromptUpdateSleep);
      this.settings.set("oaiPromptCmd", data.oaiPromptCmd);
    } catch (error) {
      console.error("[ERROR] fetching prompt:", error);
    }
  }

  /**
   * 發送GPT請求
   */
  async sendGptRequest(systemPrompt, userPrompt) {
    const useSystemMode = this.settings.getBool("oaiPromptSystemMode");
    const messages = [
      {
        role: useSystemMode ? "system" : "user",
        content: systemPrompt,
      },
      {
        role: "user",
        content: userPrompt,
      },
    ];

    return this.makeGptRequest(messages);
  }

  /**
   * 發送GPT陣列請求
   */
  async sendGptArrayRequest(messages) {
    return this.makeGptRequest(messages);
  }

  /**
   * 執行GPT請求
   */
  async makeGptRequest(messages) {
    return new Promise((resolve) => {
      const apiKey = this.settings.get("oaiKey");

      GM_xmlhttpRequest({
        method: "POST",
        url: this.settings.get("oaiBaseUrl"),
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${apiKey}`,
        },
        data: JSON.stringify({
          messages,
          max_tokens: 4090,
          model: this.settings.get("oaiModel"),
          stream: false,
          temperature: 0.7,
          presence_penalty: 0,
          frequency_penalty: 0,
        }),
        timeout: 30000,
        onload: (response) => {
          try {
            if (response.status !== 200) {
              console.error(`伺服器回應錯誤: ${response.status}`);
              alert("取得 GPT 回覆時發生錯誤,請稍後再試。");
              resolve({ response: false, data: null });
              return;
            }

            const data = JSON.parse(response.responseText);
            if (data?.choices?.[0]?.message?.content) {
              resolve({ response: true, data });
            } else {
              console.error("API 返回的數據格式不正確");
              alert("取得 GPT 回覆時發生錯誤,請稍後再試。");
              resolve({ response: false, data: null });
            }
          } catch (error) {
            console.error("取得 GPT 回覆時發生錯誤:", error);
            alert("取得 GPT 回覆時發生錯誤,請稍後再試。");
            resolve({ response: false, data: null });
          }
        },
        onerror: (error) => {
          console.error("取得 GPT 回覆時發生錯誤:", error);
          alert("取得 GPT 回覆時發生錯誤,請稍後再試。");
          resolve({ response: false, data: null });
        },
        ontimeout: () => {
          console.error("取得 GPT 回覆超時");
          alert("取得 GPT 回覆時發生錯誤,請稍後再試。");
          resolve({ response: false, data: null });
        },
      });
    });
  }

  /**
   * 工具方法:創建按鈕
   */
  createButton({
    text,
    icon,
    id,
    className = "article-footer_right-btn",
    style = {},
    insertPosition = null,
  }) {
    const button = document.createElement("a");
    button.classList.add(className);
    button.innerHTML = `<i class="material-icons lazyBtn">${icon}</i><p>${text}</p>`;
    button.id = id;

    Object.assign(button.style, {
      display: "flex",
      alignItems: "center",
      ...style,
    });

    return button;
  }

  /**
   * 工具方法:創建摘要文章
   */
  createSummaryArticle(id, content) {
    const article = document.createElement("article");
    article.classList.add("c-article", "FM-P2");
    article.id = id;

    Object.assign(article.style, {
      display: "block",
      overflow: "hidden",
      maxHeight: "auto",
      minHeight: "0px",
    });

    const articleContent = document.createElement("div");
    articleContent.classList.add("c-article__content");
    articleContent.style.whiteSpace = "pre-wrap";
    articleContent.innerHTML = content;

    article.appendChild(articleContent);
    return article;
  }

  /**
   * 工具方法:創建留言摘要文章
   */
  createCommentSummaryArticle(id, content) {
    const article = document.createElement("article");
    article.classList.add("c-reply__item", "c-article", "FM-P2");
    article.id = id;

    Object.assign(article.style, {
      display: "block",
      overflow: "hidden",
      maxHeight: "auto",
      minHeight: "0px",
    });

    const articleContent = document.createElement("div");
    articleContent.classList.add("c-article__content");
    articleContent.style.whiteSpace = "pre-wrap";
    articleContent.innerHTML = content;

    article.appendChild(articleContent);
    return article;
  }

  /**
   * 工具方法:提取文章內容
   */
  extractArticleContent(postBody) {
    const articleContent = postBody.querySelector(".c-article__content");
    let textContent = "";

    articleContent.childNodes.forEach((node) => {
      textContent += node.textContent.trim() + "\n";
    });

    return textContent.replace(/\n+/g, "\n");
  }

  /**
   * 工具方法:驗證API密鑰
   */
  validateApiKey() {
    const apiKey = this.settings.get("oaiKey");
    if (apiKey === "sk-yourKey" || apiKey === "") {
      alert("請先設定 API Key 才能使用 AI 功能");
      return false;
    }
    return true;
  }

  /**
   * 工具方法:處理切換邏輯
   */
  handleToggleLogic(button, elementId, defaultText = null) {
    const element = document.getElementById(elementId);
    const buttonText = button.querySelector("p").textContent;

    if (element && buttonText === "摺疊 ▲") {
      this.toggleElement(element);
      button.querySelector("p").textContent = "展開 ▼";
      return true;
    }

    if (element && buttonText === "展開 ▼") {
      this.toggleElement(element);
      button.querySelector("p").textContent = "摺疊 ▲";
      return true;
    }

    if (element && buttonText !== (defaultText || "懶人包")) {
      return true;
    }

    return false;
  }

  /**
   * 工具方法:滾動到元素
   */
  scrollToElement(element, marginOffset = 7) {
    const originalMargin = element.style.marginTop || "0px";
    element.style.marginTop = `-${marginOffset}rem`;
    element.scrollIntoView({ behavior: "smooth" });
    element.style.marginTop = originalMargin;
    // 檢查是否在視窗內,如果不是則重新滾動
    setTimeout(() => {
      if (!UtilityFunctions.isInViewport(element)) {
        this.scrollToElement(element, marginOffset);
      }
    }, 700);
  }

  /**
   * 工具方法:動畫元素
   */
  async animateElement(
    element,
    show = true,
    animation = "ud",
    waitForAppend = true
  ) {
    if (waitForAppend) {
      requestAnimationFrame(() => {
        this.setElementDimensions(element);
      });
    } else {
      this.setElementDimensions(element);
    }

    this.setupElementAnimation(element, show, animation);
  }

  /**
   * 工具方法:設置元素尺寸
   */
  setElementDimensions(element) {
    element.style.readHeight =
      element.scrollHeight === 0 ? "999px" : `${element.scrollHeight}px`;
    element.style.readWidth =
      element.scrollWidth === 0 ? "999px" : `${element.scrollWidth}px`;
  }

  /**
   * 工具方法:設置元素動畫
   */
  setupElementAnimation(element, show, animation) {
    Object.assign(element.style, {
      transition: "",
      overflow: "hidden auto",
      opacity: "0",
    });

    this.toggleElement(element, false, animation);
    element.style.transition =
      "all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s";

    if (!show) {
      element.style.beeShow = "false";
      return;
    }

    element.style.beeShow = "true";
    element.style.opacity = "1";

    requestAnimationFrame(() => {
      element.style.maxHeight = element.style.readHeight;
    });
  }

  /**
   * 工具方法:切換元素顯示
   */
  toggleElement(element, show = null, animation = "ud") {
    const shouldShow =
      show === null ? !(element.style.beeShow === "true") : show;

    if (shouldShow) {
      Object.assign(element.style, {
        opacity: "1",
        maxHeight: element.style.readHeight,
        maxWidth: element.style.readWidth,
        transform: "translateX(0px) translateY(0px)",
        beeShow: "true",
      });
    } else {
      element.style.beeShow = "false";
      element.style.opacity = "0";

      if (animation.includes("u")) {
        element.style.maxHeight = "0px";
        if (animation.startsWith("d")) {
          element.style.transform = `translateX(0px) translateY(${element.style.readWidth}px)`;
        }
      }

      if (animation.includes("l")) {
        element.style.maxWidth = "0px";
        if (animation.startsWith("r")) {
          element.style.transform = `translateX(${element.style.readHeight}) translateY(0px)`;
        }
      }
    }
  }
}
/**
 * 設定管理與UI模組
 * 負責插件設定介面、提示系統、檢舉提醒等功能
 */
class SettingsUIManager {
  constructor(settings) {
    this.settings = settings;
  }

  /**
   * 添加設定元素到頁面
   */
  async addSettingElement(isNewVersion) {
    const uiElements = this.createUIElements(isNewVersion);
    if (!uiElements) return;

    const { navAdd, settingsContainer } = uiElements;

    this.setupEventListeners(navAdd, settingsContainer, isNewVersion);
    this.createSettingsContent(settingsContainer, isNewVersion);

    await this.initializeSettingsContainer(settingsContainer);
  }

  /**
   * 創建UI元素
   */
  createUIElements(isNewVersion) {
    if (isNewVersion) {
      return this.createNewVersionUI();
    } else if (document.querySelector(".b-list") !== null) {
      return this.createOldVersionUI();
    }
    return null;
  }

  /**
   * 創建新版UI
   */
  createNewVersionUI() {
    const navAddTag = document.querySelector(".forum-nav-main");
    const settingsWarp = document.querySelector(".forum-header");

    if (!navAddTag || !settingsWarp) return null;

    // 創建設定按鈕
    const navAdd = document.createElement("li");
    navAdd.className = "forum-nav-link forum-nav-rules beeSettingTag";
    navAdd.innerHTML = "插件設定";
    navAdd.style.cursor = "pointer";
    navAddTag.appendChild(navAdd);

    // 創建設定容器
    const settingsContainer = this.createSettingsContainer(
      "forum-filter-box beeSettingWarp"
    );
    settingsWarp.appendChild(settingsContainer);

    // 添加提示標題
    const sectionTitle = document.createElement("h3");
    sectionTitle.className = "section-title";
    sectionTitle.textContent = "滾動下拉還有哦!";
    sectionTitle.style.margin = "0.6rem 0 0.7rem 0.7rem";
    settingsContainer.appendChild(sectionTitle);

    return { navAdd, settingsContainer };
  }

  /**
   * 創建舊版UI
   */
  createOldVersionUI() {
    const navAddTag = document.querySelector(".BH-menuE");
    const settingsWarp = document.querySelector(".b-list-wrap");

    if (!navAddTag || !settingsWarp) return null;

    // 創建設定按鈕
    const navAdd = document.createElement("li");
    navAdd.className = "beeSettingTag";
    navAdd.innerHTML = "插件設定";
    navAdd.style.cursor = "pointer";
    navAddTag.appendChild(navAdd);

    // 創建設定容器
    const settingsContainer = this.createSettingsContainer(
      "forum-filter-box beeSettingWarp"
    );
    settingsWarp.insertBefore(settingsContainer, settingsWarp.firstChild);

    // 添加提示標題
    const sectionTitle = document.createElement("h3");
    sectionTitle.className = "section-title";
    sectionTitle.textContent =
      "插件設定(再點一次上方的【插件設定】即可返回【文章列表】)";
    sectionTitle.style.margin = "0.6rem 0 0.7rem 0.7rem";
    settingsContainer.appendChild(sectionTitle);

    return { navAdd, settingsContainer };
  }

  /**
   * 創建設定容器
   */
  createSettingsContainer(className) {
    const container = document.createElement("div");
    container.className = className;

    Object.assign(container.style, {
      maxHeight: "0px",
      overflow: "hidden auto",
    });

    return container;
  }

  /**
   * 設置事件監聽器
   */
  setupEventListeners(navAdd, settingsContainer, isNewVersion) {
    navAdd.addEventListener("click", () => {
      if (isNewVersion) {
        this.toggleNewVersionSettings(settingsContainer);
      } else {
        this.toggleOldVersionSettings(settingsContainer);
      }
    });
  }

  /**
   * 切換新版設定顯示
   */
  toggleNewVersionSettings(container) {
    if (container.style.maxHeight === "0px") {
      container.style.maxHeight = "60vh";
      container.style.opacity = "1";
    } else {
      container.style.maxHeight = "0px";
      container.style.opacity = "0";
    }
  }

  /**
   * 切換舊版設定顯示
   */
  toggleOldVersionSettings(container) {
    const animationManager = new AnimationManager();
    animationManager.popElement(container, "toggle", "ud");

    const scrollTarget =
      document.getElementById("BH-master") ||
      document.querySelector(".b-list-wrap");
    if (scrollTarget) {
      this.scrollToElement(scrollTarget, 7);
    }
  }

  /**
   * 創建設定內容
   */
  createSettingsContent(container, isNewVersion) {
    this.addBasicSettings(container, isNewVersion);
    this.addLayoutSettings(container);
    this.addAISettings(container);
    this.addMiscSettings(container, isNewVersion);
    this.addReloadButton(container, isNewVersion);
  }

  /**
   * 添加基本設定
   */
  addBasicSettings(container, isNewVersion) {
    if (!isNewVersion) {
      container.appendChild(
        this.createItemCard("add_function", "標題後方插入功能按鈕")
      );
      container.appendChild(
        this.createItemCard("preview_auto", "點擊文章時使用即時瀏覽")
      );
      container.appendChild(
        this.createItemCard(null, null, {
          inputId: "preview_size",
          labelText: " └ 即時瀏覽視窗的大小",
        })
      );
    } else {
      container.appendChild(
        this.createItemCard("cleanMode", "清爽模式(隱藏文章描述和縮圖)")
      );
      container.appendChild(
        this.createItemCard(null, null, {
          inputId: "cleanModeSize",
          labelText: " └ 清爽模式文章清單大小",
        })
      );
      container.appendChild(
        this.createItemCard(null, null, {
          inputId: "preview_size",
          labelText: "即時瀏覽視窗的大小",
        })
      );
    }

    container.appendChild(
      this.createItemCard("preview_LR", "即時瀏覽從右方彈出(取消則從左)")
    );
  }

  /**
   * 添加版面設定
   */
  addLayoutSettings(container) {
    container.appendChild(
      this.createItemCard("new_design", "自訂板面大小(附加浮動型聊天室)")
    );

    const layoutSettings = [
      {
        inputId: "new_design_box",
        labelText: " └ 整體顯示區域佔比(文章+聊天室佔整個畫面的比例,< 100%)",
      },
      {
        inputId: "new_design_box_Left",
        labelText: " ├ 文章佔比(與聊天室佔比總和 <= 100%)",
      },
      {
        inputId: "new_design_box_Right",
        labelText: " └ 聊天室佔比",
      },
    ];

    layoutSettings.forEach((setting) => {
      container.appendChild(this.createItemCard(null, null, setting));
    });

    container.appendChild(
      this.createItemCard("new_design_LRSwitch", "聊天室在左方")
    );
  }

  /**
   * 添加AI設定
   */
  addAISettings(container) {
    container.appendChild(
      this.createItemCard(
        "addSummaryBtn",
        "跳過樓層按鈕/AI總結(AI功能需自備KEY填入下方)"
      )
    );

    const aiSettings = [
      { inputId: "oaiBaseUrl", labelText: " ├ oai URL" },
      { inputId: "oaiModel", labelText: " ├ oai model" },
      { inputId: "oaiKey", labelText: " ├ oai key" },
      {
        inputId: "custom_oaiPrompt",
        labelText: " ├ 「懶人包」提示詞(留空=預設)",
      },
      {
        inputId: "custom_oaiPromptCmd",
        labelText: " ├ 「留言統整」自訂提示詞(留空=預設)",
      },
      {
        inputId: "custom_oaiPromptChat",
        labelText: " ├ 「問問」自訂提示詞(留空=預設)",
      },
    ];

    aiSettings.forEach((setting) => {
      container.appendChild(this.createItemCard(null, null, setting));
    });

    container.appendChild(
      this.createItemCard("oaiPromptSystemMode", "├ 自訂提示詞使用 system 模式")
    );

    container.appendChild(
      this.createItemCard(null, null, {
        inputId: "oaiPromptUpdateURL",
        labelText: " └ oai prompt settings URL",
      })
    );
  }

  /**
   * 添加雜項設定
   */
  addMiscSettings(container, isNewVersion) {
    if (!isNewVersion) {
      container.appendChild(
        this.createItemCard("addBorderInPicMode", "縮圖列表模式中,加上分隔線")
      );
      container.appendChild(
        this.createItemCard("showAbuse", "有檢舉時,自動以即時瀏覽開啟")
      );
    }

    container.appendChild(this.createItemCard("showTips", "重新觀看TIPs"));
  }

  /**
   * 添加重載按鈕
   */
  addReloadButton(container, isNewVersion) {
    const reloadBtn = document.createElement("button");
    reloadBtn.textContent = "重整頁面以生效";

    if (!isNewVersion) {
      reloadBtn.style.margin = "0.5rem 0 0.7rem 0.7rem";
      reloadBtn.style.color = "white";
    }

    reloadBtn.addEventListener("click", () => {
      location.reload();
    });

    const reloadBtnDiv = document.createElement("div");
    reloadBtnDiv.className = isNewVersion
      ? "btn btn-primary"
      : "BH-rbox BH-qabox1";
    reloadBtnDiv.appendChild(reloadBtn);
    container.appendChild(reloadBtnDiv);
  }

  /**
   * 創建設定項目卡片
   */
  createItemCard(inputId, labelText, additionalContent = null) {
    const itemCard = document.createElement("div");
    itemCard.className =
      "item-card management_guild-check single-choice forum-filter-group";

    const checkGroup = document.createElement("div");
    checkGroup.className = "check-group";
    checkGroup.style.margin = "0rem 0 0.1rem 0.7rem";

    if (inputId) {
      this.createCheckboxInput(checkGroup, inputId, labelText);
    }

    if (additionalContent) {
      this.createTextInput(checkGroup, additionalContent);
    }

    itemCard.appendChild(checkGroup);
    return itemCard;
  }

  /**
   * 創建複選框輸入
   */
  createCheckboxInput(container, inputId, labelText) {
    const input = document.createElement("input");
    input.id = inputId;
    input.type = "checkbox";
    input.checked = this.settings.getBool(inputId);

    const label = document.createElement("label");
    label.htmlFor = inputId;
    label.className = "is-active";

    const labelIcon = document.createElement("div");
    labelIcon.className = "label-icon";

    const icon = document.createElement("i");
    icon.className = "fa fa-check";
    labelIcon.appendChild(icon);

    const h6 = document.createElement("h6");
    h6.textContent = labelText;

    Object.assign(h6.style, {
      display: "inline-block",
      color: "var(--primary-text)",
      fontSize: "100%",
    });

    label.appendChild(labelIcon);
    label.appendChild(h6);
    container.appendChild(input);
    container.appendChild(label);

    // 添加事件監聽器
    input.addEventListener("input", () => {
      this.settings.set(inputId, input.checked.toString());
    });
  }

  /**
   * 創建文字輸入
   */
  createTextInput(container, config) {
    const h6 = document.createElement("h6");
    h6.textContent = config.labelText;
    h6.style.display = "inline-block";
    container.appendChild(h6);

    const input = document.createElement("input");
    input.className = "form-control";
    input.id = config.inputId;
    input.type = "text";
    input.size = 25;

    Object.assign(input.style, {
      margin: "0px",
      width: config.inputId.startsWith("custom_") ? "auto" : "70px",
    });

    input.value = this.settings.get(config.inputId) || "";
    container.appendChild(input);

    // 添加事件監聽器
    input.addEventListener("input", () => {
      this.settings.set(config.inputId, input.value);
    });
  }

  /**
   * 初始化設定容器
   */
  async initializeSettingsContainer(container) {
    const animationManager = new AnimationManager();
    await animationManager.popElementInit(container, false, "ud");
  }

  /**
   * 滾動到元素
   */
  scrollToElement(element, marginOffset = 7) {
    const originalMargin = element.style.marginTop || "0px";
    element.style.marginTop = `-${marginOffset}rem`;
    element.scrollIntoView({ behavior: "smooth" });
    element.style.marginTop = originalMargin;

    setTimeout(() => {
      if (!UtilityFunctions.isInViewport(element)) {
        this.scrollToElement(element, marginOffset);
      }
    }, 300);
  }
}

/**
 * 提示系統管理器
 */
class TipsManager {
  constructor(settings) {
    this.settings = settings;
  }

  /**
   * 檢查並載入提示
   */
  checkTips(isNewVersion) {
    if (this.shouldShowBPageTips()) {
      this.loadBPageTips();
      this.settings.set("showTips", "false");
    }

    if (this.shouldShowHomeTips()) {
      this.loadHomeTips();
      this.settings.set("homeTips", "false");
    }
  }

  /**
   * 檢查是否應顯示B頁提示
   */
  shouldShowBPageTips() {
    return (
      window.location.href.includes("forum.gamer.com.tw/B.php") &&
      this.settings.getBool("showTips")
    );
  }

  /**
   * 檢查是否應顯示首頁提示
   */
  shouldShowHomeTips() {
    return (
      window.location.href.includes("www.gamer.com.tw") &&
      this.settings.getBool("homeTips")
    );
  }

  /**
   * 載入B頁提示
   */
  loadBPageTips() {
    this.loadDriverJS(() => {
      this.createBPageTour();
    });
  }

  /**
   * 載入首頁提示
   */
  loadHomeTips() {
    this.loadDriverJS(() => {
      this.createHomeTour();
    });
  }

  /**
   * 載入Driver.js庫
   */
  loadDriverJS(callback) {
    // 載入CSS
    const link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/driver.css";
    document.head.appendChild(link);

    // 載入JS
    const script = document.createElement("script");
    script.src =
      "https://cdn.jsdelivr.net/npm/[email protected]/dist/driver.js.iife.js";
    script.onload = callback;
    document.head.appendChild(script);
  }

  /**
   * 創建B頁導覽
   */
  createBPageTour() {
    const picMode = document.querySelectorAll(".imglist-text").length !== 0;
    const driver = window.driver.js.driver;

    const driverObj = driver({
      showButtons: ["next", "previous"],
      allowClose: false,
      nextBtnText: "▶",
      prevBtnText: "◀",
      doneBtnText: "好耶",
      showProgress: true,
      steps: this.getBPageTourSteps(picMode),
    });

    driverObj.drive();
  }

  /**
   * 獲取B頁導覽步驟
   */
  getBPageTourSteps(picMode) {
    return [
      {
        element: ".beeSettingTag",
        popover: {
          title: "客製化設定",
          description:
            "在這裡可以進行詳細的個人設定,設定變更後需要【重新整理】頁面才會生效。",
        },
      },
      {
        element: picMode
          ? "#BH-master > form > div > table > tbody > tr > td.b-list__main > div > div > p"
          : "#BH-master > form > div > table > tbody > tr > td.b-list__main > a",
        popover: {
          title: "即時瀏覽",
          description:
            "如果開啟「點擊時使用即時預覽」,文章標題的跳轉會以即時預覽的方式啟動。",
          side: "bottom",
        },
      },
      {
        element:
          "#BH-master > form > div > table > tbody > tr > td.b-list__main",
        popover: {
          title: "快速選取",
          description:
            "除了文章標題、縮圖模式的預覽圖,其他區域可以觸發快速選取。功能等同左方的勾選方塊。",
          side: "bottom",
          onNextClick: () => {
            this.showFunctionButtons();
            driverObj.moveNext();
          },
        },
      },
      {
        element: picMode
          ? "#BH-master > form > div > table > tbody > tr:nth-child(2) > td:nth-child(3)"
          : "#BH-master > form > div > table > tbody > tr:nth-child(2) > td:nth-child(3)",
        popover: {
          title: "功能按鈕",
          description:
            "如果開啟「插入功能按鈕」,指標指向的文章後方會出現三個功能按鈕,分別是「即時預覽」「新分頁開啟」「複製連結」。",
          side: "bottom",
          onNextClick: () => {
            this.hideFunctionButtons();
            this.clickPreviewButton(picMode);
            driverObj.moveNext();
          },
        },
      },
      {
        element: "#BH-master > form > section:last-child > div",
        popover: {
          title: "功能選單",
          description: "快速預覽視窗中,功能選單會漂浮在下方,方便使用!",
          side: "bottom",
          onPrevClick: () => {
            this.closePreviewer();
            this.showFunctionButtons();
            driverObj.movePrevious();
          },
          onNextClick: () => {
            this.closePreviewer();
            driverObj.moveNext();
          },
        },
      },
    ];
  }

  /**
   * 顯示功能按鈕
   */
  showFunctionButtons() {
    const buttons = [".bee_preview", ".bee_open_new_wd", ".bee_link"];

    buttons.forEach((selector) => {
      const button = document.querySelector(
        `#BH-master > form > div > table > tbody > tr:nth-child(2) > td:nth-child(3) > a.btn-icon.btn-icon--inverse${selector}`
      );
      if (button) {
        button.style.display = "inline-block";
      }
    });
  }

  /**
   * 隱藏功能按鈕
   */
  hideFunctionButtons() {
    const buttons = [".bee_preview", ".bee_open_new_wd", ".bee_link"];

    buttons.forEach((selector) => {
      const button = document.querySelector(
        `#BH-master > form > div > table > tbody > tr:nth-child(2) > td:nth-child(3) > a.btn-icon.btn-icon--inverse${selector}`
      );
      if (button) {
        button.style.display = "none";
      }
    });
  }

  /**
   * 點擊預覽按鈕
   */
  clickPreviewButton(picMode) {
    const selector = picMode
      ? "#BH-master > form > div > table > tbody > tr:nth-child(2) > td.b-list__main > div > a"
      : "#BH-master > form > div > table > tbody > tr:nth-child(2) > td.b-list__main > a";

    const button = document.querySelector(selector);
    if (button) {
      button.click();
    }
  }

  /**
   * 關閉預覽器
   */
  closePreviewer() {
    const closeButton = document.querySelector("#BH-menu-path");
    if (closeButton) {
      closeButton.click();
    }
  }

  /**
   * 創建首頁導覽
   */
  createHomeTour() {
    const driver = window.driver.js.driver;

    const driverObj = driver({
      showButtons: ["next", "previous"],
      allowClose: false,
      nextBtnText: "▶",
      prevBtnText: "◀",
      doneBtnText: "好耶",
      showProgress: true,
      steps: [
        {
          element: "#homeStyleSwitch",
          popover: {
            title: "滿版首頁",
            description: "點此可以切換首頁排版。",
          },
        },
      ],
    });

    driverObj.drive();
  }
}

/**
 * 檢舉提醒管理器
 */
class ReportManager {
  constructor(settings) {
    this.settings = settings;
  }

  /**
   * 檢查檢舉提醒
   */
  checkAlert(isNewVersion) {
    if (!this.shouldCheckReport()) return;

    const isReported = this.detectReport();
    if (!isReported) return;

    const bsn = this.extractBsn();
    if (!bsn) {
      console.log("[WARN] 有檢舉但抓取連結失敗");
      return;
    }

    this.openReportPage(bsn);
  }

  /**
   * 檢查是否應該檢查檢舉
   */
  shouldCheckReport() {
    return (
      window.location.href.includes("forum.gamer.com.tw/B.php") &&
      this.settings.getBool("showAbuse")
    );
  }

  /**
   * 檢測是否有檢舉
   */
  detectReport() {
    const reportElement = document.querySelector(
      "#BH-slave > div.BH-rbox.FM-rbox14 > div.FM-master-btn > a > span"
    );
    return reportElement !== null;
  }

  /**
   * 提取BSN參數
   */
  extractBsn() {
    const urlParams = new URLSearchParams(window.location.search);
    return urlParams.get("bsn");
  }

  /**
   * 開啟檢舉頁面
   */
  openReportPage(bsn) {
    // 這裡需要使用全域的openInFrame函數
    if (typeof openInFrame === "function") {
      openInFrame(`https://forum.gamer.com.tw/gemadmin/accuse.php?bsn=${bsn}`);
    }
  }
}

/**
 * 動畫管理器
 */
class AnimationManager {
  /**
   * 彈出元素初始化
   */
  async popElementInit(element, show = true, anime = "ud", waitAppend = true) {
    if (waitAppend) {
      requestAnimationFrame(() => {
        this.setElementDimensions(element);
      });
    } else {
      this.setElementDimensions(element);
    }

    this.setupElementTransition(element, show, anime);
  }

  /**
   * 設置元素尺寸
   */
  setElementDimensions(element) {
    element.style.readHeight =
      element.scrollHeight === 0 ? "999px" : `${element.scrollHeight}px`;
    element.style.readWidth =
      element.scrollWidth === 0 ? "999px" : `${element.scrollWidth}px`;
  }

  /**
   * 設置元素過渡
   */
  setupElementTransition(element, show, anime) {
    Object.assign(element.style, {
      transition: "",
      overflow: "hidden auto",
      opacity: "0",
    });

    this.popElement(element, "false", anime);
    element.style.transition =
      "all 0.5s cubic-bezier(0.21, 0.3, 0.18, 1.37) 0s";

    if (!show) {
      element.style.beeShow = "false";
      return;
    }

    element.style.beeShow = "true";
    element.style.opacity = "1";

    requestAnimationFrame(() => {
      element.style.maxHeight = element.style.readHeight;
    });
  }

  /**
   * 彈出元素控制
   */
  popElement(element, show = "true", anime = "ud") {
    const doShow =
      show === "toggle" ? !(element.style.beeShow === "true") : show === "true";

    if (doShow) {
      this.showElement(element);
    } else {
      this.hideElement(element, anime);
    }
  }

  /**
   * 顯示元素
   */
  showElement(element) {
    Object.assign(element.style, {
      opacity: "1",
      maxHeight: element.style.readHeight,
      maxWidth: element.style.readWidth,
      transform: "translateX(0px) translateY(0px)",
      beeShow: "true",
    });
  }

  /**
   * 隱藏元素
   */
  hideElement(element, anime) {
    element.style.beeShow = "false";
    element.style.opacity = "0";

    if (anime.includes("u")) {
      element.style.maxHeight = "0px";
      if (anime.startsWith("d")) {
        element.style.transform = `translateX(0px) translateY(${element.style.readWidth}px)`;
      }
    }

    if (anime.includes("l")) {
      element.style.maxWidth = "0px";
      if (anime.startsWith("r")) {
        element.style.transform = `translateX(${element.style.readHeight}) translateY(0px)`;
      }
    }
  }
}
/**
 * 首頁功能模組
 * 負責首頁的版面切換和樣式調整功能
 */
class HomePageWorker {
  constructor(settings) {
    this.settings = settings;
  }

  /**
   * 初始化首頁功能
   */
  init() {
    if (!this.isHomePage()) return;

    this.addStyleSwitchButton();
    this.applyHomeStyles();
  }

  /**
   * 檢查是否為首頁
   */
  isHomePage() {
    return (
      window.location.href.includes("www.gamer.com.tw") &&
      document.querySelectorAll("div.BA-lbox.BA-lbox3").length > 0
    );
  }

  /**
   * 添加樣式切換按鈕
   */
  addStyleSwitchButton() {
    const baServeElement = document.querySelector(".BA-serve");
    if (!baServeElement) return;

    const switchButton = document.createElement("li");
    switchButton.id = "homeStyleSwitch";
    switchButton.innerHTML = "首頁滿版切換";
    baServeElement.appendChild(switchButton);

    switchButton.addEventListener("click", () => {
      this.toggleHomeStyle();
    });
  }

  /**
   * 切換首頁樣式
   */
  toggleHomeStyle() {
    const currentValue = this.settings.getBool("homeStyleSwitch");
    this.settings.set("homeStyleSwitch", (!currentValue).toString());
    location.reload();
  }

  /**
   * 應用首頁樣式
   */
  applyHomeStyles() {
    if (!this.settings.getBool("homeStyleSwitch")) return;

    this.reorganizeContainers();
    this.createSecondLeftNav();
    this.addCustomStyles();
  }

  /**
   * 重新組織容器
   */
  reorganizeContainers() {
    const hotboardContainer = document.getElementById("hotboardContainer");
    const guildContainer = document.getElementById("guildContainer");
    const hothalaContainer = document.getElementById("hothalaContainer");

    if (hotboardContainer && guildContainer && hothalaContainer) {
      hothalaContainer.appendChild(hotboardContainer);
      hothalaContainer.appendChild(guildContainer);
    }
  }

  /**
   * 創建第二個左側導航
   */
  createSecondLeftNav() {
    const bahaStoreContainer = document.querySelectorAll(
      "div.BA-lbox.BA-lbox3"
    )[0];
    const bahaAnimeContainer = document.querySelectorAll(
      "div.BA-lbox.BA-lbox3"
    )[1];
    const titles = document.querySelectorAll("h1.BA-ltitle");
    const wrapper = document.querySelectorAll("div.BA-wrapper.BA-main")[0];
    const center = document.querySelectorAll("div.BA-center")[0];

    if (!bahaStoreContainer || !bahaAnimeContainer || !wrapper || !center)
      return;

    const secondDivLeft = document.createElement("div");
    secondDivLeft.className = "BA-left";

    Object.assign(secondDivLeft.style, {
      flex: "0 0 11em",
      margin: "0 0 0 1em",
    });

    // 添加標題和容器
    if (titles[1]) secondDivLeft.appendChild(titles[1]);
    secondDivLeft.appendChild(bahaAnimeContainer);
    if (titles[0]) secondDivLeft.appendChild(titles[0]);
    secondDivLeft.appendChild(bahaStoreContainer);

    wrapper.insertBefore(secondDivLeft, center);
  }

  /**
   * 添加自定義樣式
   */
  addCustomStyles() {
    const styleElement = document.createElement("style");
    styleElement.textContent = this.getCustomCSS();
    document.head.appendChild(styleElement);
  }

  /**
   * 獲取自定義CSS
   */
  getCustomCSS() {
    return `
            /* 父容器設置 */
            .BA-wrapper.BA-main {
                display: flex;
                flex-wrap: wrap;
                width: auto;
            }

            /* 第一層左側固定寬度 */
            .BA-left {
                flex: 0 0 11em;
            }

            /* 第一層右側容器 */
            .BA-center {
                flex: 1;
                display: flex;
                flex-wrap: wrap;
            }

            #gnnContainer {
                flex: 0 0 45%;
                margin: 0 1% 2% 1%;
                order: 1;
            }

            #hothalaContainer {
                flex: 45%;
                margin: 0 1% 2% 1%;
                order: 2;
            }

            #homeContainer {
                flex: 45%;
                margin: 0 1% 2% 1%;
                order: 3;
            }

            #buyContainer {
                flex: 0 0 45%;
                margin: 0 1% 2% 1%;
                order: 4;
            }

            #liveContainer {
                flex: 45%;
                margin: 0 1% 2% 1%;
                order: 5;
            }

            #gamecrazyContainer {
                flex: 0 0 45%;
                margin: 0 1% 2% 1%;
                order: 6;
            }

            .BA-cbox7 p {
                text-align: left !important;
            }
        `;
  }
}

/**
 * 工具函數模組
 * 提供全域使用的工具函數
 */
class UtilityFunctions {
  /**
   * 在框架中打開URL(全域函數)
   */
  static openInFrame(url) {
    const iframe = document.getElementById("bee_frame");
    if (!iframe) return;

    iframe.src = url;

    const menuPath = document.querySelector("#BH-menu-path");
    if (menuPath) {
      menuPath.style.height = "100%";
      menuPath.style.opacity = "0.6";
    }

    setTimeout(() => {
      const container = document.querySelector(".bee_preview_wd");
      if (container) {
        const animationManager = new AnimationManager();
        const direction =
          localStorage.getItem("preview_LR") === "true" ? "rl" : "lr";
        animationManager.popElement(container, "true", direction);
      }
    }, 1000);

    // 設置iframe樣式
    setTimeout(() => {
      UtilityFunctions.setupIframeStyles(iframe);
    }, 1000);
  }

  /**
   * 設置iframe樣式
   */
  static setupIframeStyles(iframe) {
    try {
      const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
      const styleSheet = iframeDoc.createElement("style");
      iframeDoc.head.appendChild(styleSheet);

      const sheet = styleSheet.sheet;
      sheet.insertRule(
        ".managertools { position: fixed; bottom: 0; right: 0; z-index: 100; }",
        0
      );
    } catch (error) {
      console.warn("無法設置iframe樣式:", error);
    }
  }

  /**
   * 滾動到指定元素
   */
  static scrollIntoBee(element, marginOffset = 7) {
    const originalMargin = element.style.marginTop || "0px";
    element.style.marginTop = `-${marginOffset}rem`;
    element.scrollIntoView({ behavior: "smooth" });
    element.style.marginTop = originalMargin;

    setTimeout(() => {
      if (!UtilityFunctions.isInViewport(element)) {
        UtilityFunctions.scrollIntoBee(element, marginOffset);
      }
    }, 300);
  }

  /**
   * 檢查元素是否在視窗內
   */
  static isInViewport(element) {
    const rect = element.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.top <= (window.innerHeight || document.documentElement.clientHeight)
    );
  }

  /**
   * 還原原始格式(用於留言處理)
   */
  static restoreOriginalFormat(textContent, cmdContents) {
    const nameToHtmlMap = new Map();
    const htmlPattern = /([^<]+)<\/a>/g;
    let match;

    while ((match = htmlPattern.exec(cmdContents)) !== null) {
      nameToHtmlMap.set(match[1], match[0]);
    }

    let processedText = textContent;
    nameToHtmlMap.forEach((html, name) => {
      const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
      const atPattern = new RegExp(`@${escapedName}`, "g");
      processedText = processedText.replace(atPattern, html);
    });

    return processedText;
  }

  /**
   * 格式化日期
   */
  static formatDate(date) {
    return date.toISOString().slice(0, 10).replace(/-/g, "");
  }

  /**
   * 安全獲取元素
   */
  static safeQuerySelector(selector) {
    try {
      return document.querySelector(selector);
    } catch (error) {
      console.warn(`無法找到元素: ${selector}`, error);
      return null;
    }
  }

  /**
   * 安全獲取多個元素
   */
  static safeQuerySelectorAll(selector) {
    try {
      return document.querySelectorAll(selector);
    } catch (error) {
      console.warn(`無法找到元素: ${selector}`, error);
      return [];
    }
  }

  /**
   * 防抖函數
   */
  static debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  /**
   * 節流函數
   */
  static throttle(func, limit) {
    let inThrottle;
    return function (...args) {
      if (!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => (inThrottle = false), limit);
      }
    };
  }

  /**
   * 深拷貝對象
   */
  static deepClone(obj) {
    if (obj === null || typeof obj !== "object") return obj;
    if (obj instanceof Date) return new Date(obj.getTime());
    if (obj instanceof Array)
      return obj.map((item) => UtilityFunctions.deepClone(item));
    if (typeof obj === "object") {
      const clonedObj = {};
      for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
          clonedObj[key] = UtilityFunctions.deepClone(obj[key]);
        }
      }
      return clonedObj;
    }
  }

  /**
   * 生成唯一ID
   */
  static generateUniqueId(prefix = "id") {
    return `${prefix}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 等待指定時間
   */
  static sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  /**
   * 重試函數
   */
  static async retry(fn, maxRetries = 3, delay = 1000) {
    for (let i = 0; i < maxRetries; i++) {
      try {
        return await fn();
      } catch (error) {
        if (i === maxRetries - 1) throw error;
        await UtilityFunctions.sleep(delay);
      }
    }
  }

  /**
   * 檢查是否為移動設備
   */
  static isMobileDevice() {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
      navigator.userAgent
    );
  }

  /**
   * 獲取瀏覽器信息
   */
  static getBrowserInfo() {
    const ua = navigator.userAgent;
    let browser = "Unknown";

    if (ua.includes("Chrome")) browser = "Chrome";
    else if (ua.includes("Firefox")) browser = "Firefox";
    else if (ua.includes("Safari")) browser = "Safari";
    else if (ua.includes("Edge")) browser = "Edge";

    return {
      browser,
      userAgent: ua,
      isMobile: UtilityFunctions.isMobileDevice(),
    };
  }
}

/**
 * 主插件類別 - Re版本
 * 整合所有模組並提供統一的初始化入口
 */
class BahamutePluginMain extends BahamutePlugin {
  constructor() {
    super();
    //this.homePageWorker = new HomePageWorker(this.settings);
    this.settingsUIManager = new SettingsUIManager(this.settings);
    //this.tipsManager = new TipsManager(this.settings);
    this.reportManager = new ReportManager(this.settings);
  }

  /**
   * 重寫初始化方法
   */
  async init() {
    try {
      console.log("[INFO] 巴哈姆特插件開始初始化...");

      // 基礎初始化
      this.isNewVersion = await this.detectMode();
      this.settings.checkFirstRun();

      // UI初始化
      await this.settingsUIManager.addSettingElement(this.isNewVersion);

      // 功能模組初始化
      await this.initializeWorkers();
      //this.homePageWorker.init();

      // 輔助功能初始化
      //this.tipsManager.checkTips(this.isNewVersion);
      this.reportManager.checkAlert(this.isNewVersion);

      console.log("[INFO] 巴哈姆特插件初始化完成!");
    } catch (error) {
      console.error("[ERROR] 插件初始化失敗:", error);
    }
  }

  /**
   * 獲取插件版本信息
   */
  getVersionInfo() {
    return {
      version: this.version,
      isNewVersion: this.isNewVersion,
      browserInfo: UtilityFunctions.getBrowserInfo(),
      initTime: new Date().toISOString(),
    };
  }

  /**
   * 重置插件設定
   */
  resetSettings() {
    if (confirm("確定要重置所有設定嗎?這將會清除所有自定義配置。")) {
      this.settings.checkFirstRun(true);
      alert("設定已重置,請重新整理頁面。");
      location.reload();
    }
  }

  /**
   * 導出設定
   */
  exportSettings() {
    const settings = {};
    Object.keys(this.settings.defaultSettings).forEach((key) => {
      settings[key] = this.settings.get(key);
    });

    const dataStr = JSON.stringify(settings, null, 2);
    const dataBlob = new Blob([dataStr], { type: "application/json" });
    const url = URL.createObjectURL(dataBlob);

    const link = document.createElement("a");
    link.href = url;
    link.download = "bahamute-plugin-settings.json";
    link.click();

    URL.revokeObjectURL(url);
  }

  /**
   * 導入設定
   */
  importSettings(file) {
    const reader = new FileReader();
    reader.onload = (e) => {
      try {
        const settings = JSON.parse(e.target.result);
        Object.keys(settings).forEach((key) => {
          this.settings.set(key, settings[key]);
        });
        alert("設定導入成功,請重新整理頁面。");
        location.reload();
      } catch (error) {
        alert("設定文件格式錯誤,請檢查文件內容。");
      }
    };
    reader.readAsText(file);
  }
}

// 將工具函數設為全域可用
window.openInFrame = UtilityFunctions.openInFrame;
window.scrollIntoBee = UtilityFunctions.scrollIntoBee;
window.isInViewport = UtilityFunctions.isInViewport;
window.restoreOriginalFormat = UtilityFunctions.restoreOriginalFormat;

// 初始化插件(替換原本的立即執行函數)
(async function () {
  "use strict";

  // 等待DOM載入完成
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", () => {
      new BahamutePluginMain();
    });
  } else {
    new BahamutePluginMain();
  }
})();

// 開發者工具(僅在開發模式下可用)
if (typeof GM_info !== "undefined" && GM_info.script.name.includes("dev")) {
  window.BahamutePluginDev = {
    getPlugin: () => window.bahamutePluginInstance,
    resetSettings: () => window.bahamutePluginInstance?.resetSettings(),
    exportSettings: () => window.bahamutePluginInstance?.exportSettings(),
    getVersionInfo: () => window.bahamutePluginInstance?.getVersionInfo(),
    utils: UtilityFunctions,
  };
}
长期地址
遇到问题?请前往 GitHub 提 Issues。